Elasticsearch 메모리 사용량 최적화를 통한 최고 성능 달성

최고 성능을 위한 Elasticsearch 메모리 관리 마스터하기. 이 가이드에서는 JVM 힙 크기 조정, 인덱싱 및 검색 최적화, 캐싱 활용, OutOfMemory 오류 방지를 위한 서킷 브레이커 배포 등 필수적인 기술을 탐구합니다. 트래픽이 많을 때에도 Elasticsearch 클러스터가 안정적이고 응답성이 뛰어나도록 보장하는 실용적인 전략을 배우세요.

피크 성능을 위한 Elasticsearch 메모리 사용 최적화

Elasticsearch 메모리 문제는 일반적으로 느린 검색, 긴 가비지 컬렉션 일시 중지, 서킷 브레이커 오류 또는 클러스터를 떠나는 노드로 나타납니다. Elasticsearch 메모리 사용 최적화는 단순히 -Xmx를 높이는 대신 JVM 힙, 파일시스템 캐시, 샤드 수, 쿼리 동작 및 인덱싱 압력의 균형을 맞추는 것을 의미합니다.

목표는 간단합니다: Elasticsearch에 클러스터 및 쿼리 작업을 위한 충분한 힙을 제공하면서 운영 체제가 Lucene 세그먼트 파일을 캐시할 수 있도록 충분한 RAM을 남겨두는 것입니다.

Elasticsearch 메모리 구성 요소 이해

Elasticsearch는 두 가지 주요 영역에서 메모리를 사용합니다:

  • JVM 힙: 클러스터 메타데이터, 인덱싱 버퍼, 쿼리 구조, 활성화된 경우 필드데이터, 캐시 및 기타 Java 객체를 보유합니다. 힙이 너무 작으면 압력과 브레이커 트립이 발생합니다. 힙이 너무 크면 가비지 컬렉션이 길어지고 파일시스템 캐시가 부족해질 수 있습니다.
  • 파일시스템 캐시 및 네이티브 메모리: 운영 체제는 JVM 힙 외부에서 Lucene 인덱스 파일을 캐시합니다. Elasticsearch는 네트워킹, 스레드 스택 및 메모리 매핑된 파일을 위해 네이티브 메모리도 사용합니다.

JVM 힙 크기 구성

힙 크기 조정은 가장 먼저 확인해야 할 설정입니다. Elasticsearch는 설치 방법에 따라 jvm.options 파일 또는 환경별 JVM 옵션을 사용합니다.

XmsXmx를 함께 설정

-Xms-Xmx를 동일한 값으로 설정하여 노드가 실행되는 동안 JVM이 힙 크기를 조정하지 않도록 합니다.

일반적으로 힙을 물리적 RAM의 약 절반 이하로 유지하고 압축된 일반 객체 포인터 임계값을 초과하지 않도록 합니다. 실제로 많은 프로덕션 노드는 약 30GB 미만의 힙을 유지하지만, Elasticsearch 및 JVM 버전에 대한 정확한 임계값과 지침을 확인해야 합니다.

예를 들어:

-Xms4g
-Xmx4g

이것은 초기 및 최대 힙을 모두 4GB로 설정합니다.

힙 사용량 모니터링

Kibana Stack Monitoring, Prometheus 내보내기 또는 Nodes Stats API를 사용하세요:

curl -X GET "localhost:9200/_nodes/stats/jvm?pretty"

heap_used_percent, 가비지 컬렉션 시간, 구세대 압력 및 서킷 브레이커 트립을 관찰하세요. 가비지 컬렉션 후에도 오랫동안 높게 유지되는 힙은 일반적으로 힙 소비자를 줄이거나 용량을 추가해야 함을 의미합니다.

샤드 및 쿼리 메모리 압력 줄이기

인덱스 레이아웃과 쿼리 형태는 메모리에 직접적인 영향을 미칩니다.

샤드 크기 및 개수

모든 샤드에는 오버헤드가 있습니다. 너무 많은 작은 샤드는 힙을 낭비하고 클러스터 작업을 느리게 합니다. 매우 큰 샤드는 복구 및 재배치를 어렵게 만들 수 있습니다. 많은 클러스터는 수십 기가바이트 크기의 샤드에서 잘 작동하지만, 로그, 시계열 데이터 및 검색 중심 인덱스는 다른 목표가 필요할 수 있습니다.

예를 들어, 일일 로그 인덱스가 20GB 데이터에 대해 30개의 기본 샤드를 생성하는 경우 많은 작은 샤드에 대한 오버헤드를 지불하고 있는 것입니다. 보존 및 쿼리 패턴에 따라 하나 또는 두 개의 기본 샤드가 관리하기 더 쉬울 수 있습니다.

세그먼트 병합

Elasticsearch는 인덱싱을 위해 Lucene 세그먼트를 사용합니다. 작은 세그먼트는 시간이 지남에 따라 더 큰 세그먼트로 병합됩니다. 이 프로세스는 메모리 집약적일 수 있습니다. Elasticsearch가 병합을 자동으로 처리하지만, 특히 무거운 인덱싱 부하 중에는 그 영향을 이해하는 것이 유용할 수 있습니다.

검색 및 집계 최적화

  • 집계에는 키워드 필드 사용: keyword, 숫자, 날짜 또는 기타 doc-values 지원 필드에서 집계 및 정렬하세요. 힙 비용을 이해하지 않는 한 큰 text 필드에서 fielddata를 활성화하지 마세요.
  • 비용이 많이 드는 쿼리 제한: 선행 와일드카드 및 광범위한 정규 표현식 쿼리는 비용이 많이 들 수 있습니다. 부분 일치가 필요한 사용 사례에는 구조화된 필드, 접두사, n-gram 또는 search-as-you-type 매핑을 선호하세요.
  • 느린 검색 프로파일링: 스테이징 환경에서 프로필 API를 사용하여 가장 많은 작업을 생성하는 쿼리 절을 찾으세요.

캐시를 신중하게 사용

Elasticsearch에는 여러 캐시가 있습니다. 반복 작업에 도움이 되지만 메모리도 소비합니다.

  • 샤드 요청 캐시: 적격 요청에 대한 샤드 수준 검색 결과를 캐시하며, 거의 변경되지 않은 데이터에 대한 반복적인 집계 스타일 쿼리에 유용합니다. 크기는 다음으로 제어됩니다:

    indices.requests.cache.size: 5%
    

    이 예제는 샤드 요청 캐시 크기를 힙의 5%로 설정합니다.

  • 노드 쿼리 캐시: 필터 컨텍스트 결과를 캐시합니다. 크기는 별도로 제어됩니다:

    indices.queries.cache.size: 10%
    
  • 필드데이터 캐시: 힙을 소비하며 텍스트 필드에서 fielddata를 활성화하면 빠르게 커질 수 있습니다. 더 큰 fielddata 캐시에 의존하는 대신 필드를 올바르게 매핑하는 것을 선호하세요.

OutOfMemory 오류 방지

OutOfMemory 오류는 일반적으로 지속적인 압력의 최종 결과입니다. 해결책은 "모든 제한을 높이는 것"이 거의 아닙니다.

가비지 컬렉션을 증상으로 취급

최근 Elasticsearch 버전은 지원되는 JVM 기본값을 선택합니다. 버전별 지침과 측정값이 없는 한 사용자 정의 가비지 컬렉터 튜닝을 피하세요. 긴 일시 중지는 일반적으로 과도한 샤딩, 비용이 많이 드는 집계, fielddata, 너무 많은 힙 압력 또는 불충분한 노드를 가리킵니다.

GC 문제의 주요 지표는 다음과 같습니다:

  • 높은 GC 시간.
  • 긴 stop-the-world 일시 중지.
  • 각 수집 후 한계 근처로 다시 올라가는 힙 사용량.
  • 대규모 검색, 대량 인덱싱 또는 집계 중 OOM 오류.

서킷 브레이커 존중

서킷 브레이커는 메모리 사용을 추정하고 노드를 소진시키기 전에 작업을 거부합니다.

  • 필드데이터 브레이커: fielddata에 사용되는 힙을 제한합니다.
  • 요청 브레이커: 요청 데이터 구조를 완료하는 데 사용되는 메모리를 제한합니다.
  • 부모 브레이커: 결합된 브레이커 추정치를 추적합니다.

브레이커 통계 보기:

curl -X GET "localhost:9200/_nodes/stats/breaker?pretty"

클러스터 설정을 통해 일부 브레이커 설정을 변경할 수 있지만, 브레이커가 트립되는 이유를 안 후에만 수행하세요. 트립된 브레이커는 종종 노드를 OOM으로부터 보호하고 있습니다.

모니터링 및 알림

다음에 대해 알림을 설정하세요:

  • 가비지 컬렉션 후 JVM 힙 사용량.
  • 가비지 컬렉션 시간 및 긴 일시 중지.
  • 서킷 브레이커 트립.
  • 인덱싱 압력 및 거부된 스레드 풀 작업.
  • OS 메모리 압력 및 스왑 사용량.
  • 노드당 샤드 수 및 비정상적으로 큰 집계.

핵심 요점

힙 크기 조정부터 시작한 다음 샤드 수, 필드 매핑, 대규모 집계 및 반복적인 서킷 브레이커 트립을 살펴보세요. 정리 후에도 노드에 여전히 압력이 가해지면 경고 신호를 더 큰 제한으로 숨기는 대신 용량을 추가하거나 워크로드를 분할하세요.