엔지니어링

Elasticsearch 스니핑 모범 사례: 무엇을, 언제, 왜, 어떻게

Elasticsearch는 운영 분석 대시보드부터 외출할 만한 파티오가 있는 가장 가까운 식당을 보여주는 지도에 이르기까지 오늘날 사용되는 수많은 도구와 앱을 검색할 수 있도록 지원합니다. 그리고 이러한 모든 구현에서 애플리케이션과 클러스터 간의 연결은 Elasticsearch 클라이언트를 통해 이루어집니다.

클라이언트와 Elasticsearch 클러스터 간의 연결을 최적화하는 것은 최종 사용자의 경험에 극히 중요합니다. Elasticsearch 클라이언트의 일반적인 구성은 연결해야 하는 노드의 URL입니다. 하지만 여러분이 하실 수 있는 작업은 이보다 훨씬 더 많습니다, 이 연결을 최적화하는 한 가지 방법은 스니핑입니다.

스니핑이 작동하는 방법, 스니핑을 사용해야 할 때, 스니핑을 피해야 할 때를 아는 방법은 다음과 같습니다.

스니핑이란?

Elasticsearch는 분산형 시스템으로, 그 인덱스가 서로 연결된 여러 노드에 모여 클러스터를 형성하는 것을 의미합니다. 내결함성 이외에도 분산형 시스템의 주요 장점 중 하나는 데이터를 여러 노드로 공유하여 거대한 단일 노드를 통해 실행되는 검색보다 훨씬 빠르게 검색을 실행할 수 있다는 것입니다.

일반적인 클라이언트 구성은 Elasticsearch 클러스터의 하나의 노드를 가리키는 단일 URL입니다. 이 구성이 가장 간단하지만, 이 설정의 가장 큰 단점은 사용자가 요청하는 모든 요청이 해당 특정 코디네이션 노드로 전송된다는 것입니다. 이는 단일 노드에 스트레스를 주기 때문에 전반적인 성능에 영향을 미칠 수 있습니다.

한 가지 해결책은 노드의 정적 목록을 클라이언트에 전달하여 노드 간에 요청이 균등하게 분산되도록 하는 것입니다.

또는 스니핑(sniffing)이라는 기능을 활성화할 수도 있습니다.

노드의 정적 목록을 사용하면, 노드가 항상 가동되고 실행될 것이라는 보장이 없습니다. 예를 들어, 업그레이드를 위해 노드를 다운시키거나 새 노드를 추가하면 어떻게 될까요?

스니핑을 사용하도록 설정하면, 클라이언트가 _nodes/_all/http 엔드포인트를 호출하기 시작하고 응답은 클러스터에 있는 모든 노드의 목록과 그 IP 주소가 됩니다. 그러면 클라이언트는 연결 풀을 업데이트하여 모든 새 노드를 사용하고 클러스터의 상태를 클라이언트의 연결 풀과 동기화 상태로 유지합니다. 클라이언트가 노드의 전체 목록을 다운로드하더라도 마스터 전용 노드는 일반 API 호출에 사용되지 않습니다.

스니핑으로 이 발견 문제가 해결됩니다. 그렇다면 스니핑이 기본적으로 활성화되지 않는 이유는 무엇일까요? 좋은 지적입니다!

언제 스니핑을 해야 하는가?

스니핑은 양날의 칼이 될 수 있습니다. _nodes/_all/http 엔드포인트를 호출하려고 하면, 노드의 목록과 해당 엔드포인트가 표시됩니다. 하지만 다음과 같은 몇 가지 질문을 고려해야 합니다.

  • Elasticsearch 클러스터가 자체 네트워크에 있으면 어떻게 될 것인가?
  • Elasticsearch 클러스터가 로드 밸런서 뒤에 있으면 어떻게 할 것인가?

양쪽 질문 모두에 대한 간단한 대답은 다음과 같습니다. 여러분은 다른 네트워크에 있기 때문에 전혀 쓸모없는 IP 주소를 얻게 될 것입니다.

Docker에서 이를 직접 시도해 보실 수 있습니다. Elasticsearch 인스턴스(하나만 있으면 충분함)를 스핀업하고 로컬 컴퓨터에서 _nodes/_all/http를 호출합니다. 노드의 IP 주소가 방금 사용한 IP 주소와 동일하지 않다는 것을 알 수 있습니다.

다음 명령과 함께 사용하여 Elasticsearch 인스턴스를 부팅합니다.

docker run \ 
-p 9200:9200 \
-e "discovery.type=single-node" \
docker.elastic.co/elasticsearch/elasticsearch:7.8.0

이제 다음 명령으로 노드 IP를 읽을 수 있습니다. (다음 코드 조각에서는 응답을 보다 읽기 쉽게 하기 위해 jq를 사용하고 있습니다.)

curl -s localhost:9200/_nodes/_all/http | jq .nodes[].http.publish_address

마지막으로, 단말기에 인쇄된 IP 주소를 복사하여 거기로 요청을 전송할 수 있습니다.

curl {ip_address}:9200 | jq .

보시다시피, 성공적인 응답을 얻지 못합니다.

즉, 클러스터가 다른 네트워크에 있는 동안 클라이언트에서 스니핑을 활성화하면, 클라이언트는 새 노드를 모두 그 연결 풀에 추가하게 됩니다. 이는 IP 주소가 잘못되었다는 것을 이해할 방법이 없기 때문이며, 해당 노드 중 하나에 대한 모든 쿼리가 실패하게 되기 때문입니다.

올바른 IP 주소를 가진 초기 노드가 클러스터 상태에 더 이상 없으므로, 해당 노드는 폐기되고 "No living connections" 오류가 매우 빠르게 발생합니다.

하지만 이를 수정할 수 있습니다.

이 문제를 해결하려면, Elasticsearch가 해당 호스트에 바인딩되지만 다른 호스트를 애드버타이즈하도록 구성할 수 있습니다. http.publish_host 구성 옵션을 사용하면 정확히 이를 수행합니다. 이제 이 새로운 구성으로 위의 Docker 명령을 실행해 보세요.

docker run \ 
-p 9200:9200 \
-e "discovery.type=single-node" \
-e "http.publish_host=localhost" \
docker.elastic.co/elasticsearch/elasticsearch:7.8.0

이제 다음 명령을 다시 실행하면 다음과 같습니다.

curl -s localhost:9200/_nodes/_all/http | jq .nodes[].http.publish_address

터미널에는 다음과 같이 표시됩니다.

"localhost/{ip_address}:9200"

게시 호스트를 구성하면, 공식 클라이언트(v7 이상)가 IP 대신 호스트 주소를 사용할 수 있을 정도로 스마트해집니다.

이를 통해 얻을 수 있는 가장 큰 이점은 스니핑을 활성화하기 전에 인프라를 알아야 한다는 것입니다. 이 IP 주소 문제는 시스템 구성에 따라 달라지기 때문에 한 번에 완벽한 해결책은 없으며 해결 방법이 매우 많습니다.

일반적인 개발 설정은 클라이언트와 동일한 네트워크에서 Elasticsearch 클러스터를 포함하는 것이지만, 이는 보안 문제로 이어질 수 있기 때문에 실제 환경에서는 복제할 수 없으며 인프라가 더 복잡할 가능성이 높습니다. 이러한 IP 주소를 처리하도록 로드 밸런서를 구성할 수 있습니다. 또는 Elastic Cloud에서 Elastic이 하는 것처럼, 프록시가 장애 노드를 처리하도록 허용하여 클라이언트가 항상 프록시에 쿼리를 전송한 다음 적절한 노드로 쿼리를 전송할 수 있습니다.

언제 스니핑을 해서는 안되는가?

다음을 포함하여 스니핑으로 인해 문제가 발생할 수 있는 많은 상황이 있습니다.

  • 클라이언트가 인증하려는 Elasticsearch 사용자에게 노드 API에 액세스할 수 있는 권한(monitoring_user 역할)이 없습니다.
  • 여러분이 클라우드 서비스 제공자와 협력하고 있습니다.

일반적으로, 클라우드 서비스 제공자는 프록시 뒤에 Elasticsearch를 숨깁니다. 그러면 반환된 주소와 호스트 이름이 네트워크에서 아무런 의미가 없을 수 있으므로 스니핑 작업이 소용없을 수 없습니다. 일반적으로, 이러한 클라우드 서비스 제공자가 스니핑 및 풀링 복잡성을 처리하므로 여러분이 이를 지원할 필요가 없습니다.

Elastic Cloud를 사용하는 경우, 이미 수행된 작업에 시간을 낭비하지 않도록 연결 풀 처리와 같은 대부분의 작업을 공식 클라이언트가 내부적으로 단락시킵니다.

앞서 본 바와 같이, Docker 또는 Kubernetes와 함께 작업할 때 다른 문제가 발생할 수 있습니다. 게시 호스트 옵션을 구성하지 않으면, 스니핑 결과를 사용할 수 없게 됩니다.

경험 법칙에 따르면, Elasticsearch가 여러분의 클라이언트와 다른 네트워크에 있거나 로드 밸런서가 있는 경우에는, 인프라에 스니핑을 정확하게 사용할 수 있는 구성이 없는 한 스니핑을 사용하지 않도록 설정해야 합니다.

스니핑을 하는 방법

클라이언트는 여러 가지 스니핑 전략을 제시합니다. 이를 분석해 보겠습니다.

시작 시 스니핑

이름에서 알 수 있듯이, 이 옵션을 활성화하면 클라이언트는 클라이언트 초기화 또는 첫 번째 사용 중에 한 번만 스니핑 요청을 실행하려고 시도하게 됩니다.

연결 실패 시 스니핑

이 옵션을 활성화하면 클라이언트는 노드에 장애가 발생할 때마다 스니핑 요청을 실행하려고 시도하게 됩니다. 노드에 장애가 발생한다는 것은 연결이 끊어지거나 죽은 노드를 의미합니다.

스니핑 간격

시작 시 스니핑 및 실패 시 스니핑 외에도, 주기적으로 스니핑하면 클러스터가 종종 피크 시간 동안 수평으로 확장되는 시나리오에 도움이 될 수 있습니다. 애플리케이션은 노드의 부분 집합에 대한 정상적인 뷰를 가질 수 있지만, 주기적으로 스니핑하지 않으면 수평 확장의 일부로 추가된 노드를 절대 찾을 수 없게 됩니다.

사용자 정의 구성

경우에 따라, 스니핑 절차를 보다 세밀하게 제어하기를 원할 수 있습니다. 클라이언트는 여러분이 사용자 정의 스니핑 엔드포인트를 구성하도록 할 수 있을 정도로 유연하거나 스니핑 로직을 완전히 무시하고 자체적인 것 중 하나를 제공할 수 있습니다.

결론

스니핑을 활성화하면 애플리케이션이 보다 회복력이 뛰어나고 변화에 적응할 수 있게 됩니다. 스니핑을 사용하기 전에, 인프라를 알아야 채택할 수 있는 가장 좋은 솔루션이 무엇인지 결정할 수 있습니다. 가장 좋은 솔루션은 스니핑을 채택하지 않는 것입니다.

스니핑 및 연결 풀 구성에 대한 고민을 피하고 대신 간단한 연결 스트링을 사용하고 싶다면, Elastic Cloud에서 Elasticsearch Service 14일 무료 체험판을 사용해 보세요.