Elasticsearch JVM 힙 크기 이해 및 성능 튜닝

Elasticsearch JVM 힙 크기 조정, GC 증상 분석, 검색 성능을 저하시키는 메모리 설정을 피하는 실용적인 가이드

Elasticsearch JVM 힙 크기 이해 및 성능 튜닝

Elasticsearch JVM 힙 크기는 사람들이 너무 일찍 건드리고 너무 늦게 탓하는 설정 중 하나입니다. 느린 클러스터에 항상 더 많은 힙이 필요한 것은 아닙니다. 때로는 그 반대가 사실입니다. 힙은 충분히 크지만 운영 체제에 파일 시스템 캐시를 위한 메모리가 너무 적게 남아 있어 Lucene이 디스크에 더 자주 접근해야 합니다. 다른 경우에는 힙이 진정으로 너무 작아서 가비지 컬렉션이 계속 실행되고 모든 검색이 마치 젖은 시멘트를 밟는 것처럼 느껴집니다.

실용적인 목표는 마법의 숫자를 찾는 것이 아닙니다. 목표는 Elasticsearch에 클러스터 메타데이터, 인덱싱 버퍼, 집계, 쿼리 작업 및 캐시를 위한 충분한 힙을 제공하면서 Lucene 세그먼트 파일과 운영 체제를 위해 힙 외부에 충분한 RAM을 남겨두는 것입니다. 한 가지만 기억해야 한다면 Elasticsearch 성능이 힙과 오프힙 메모리 모두에 의존한다는 점을 기억하세요.

두 가지 종류의 메모리 압력을 분리하는 것부터 시작하세요. JVM 힙 압력은 높은 heap.percent, 긴 가비지 컬렉션 일시 중지, 상위 회로 차단기 예외, fielddata 압력 또는 OutOfMemoryError로 나타납니다. 오프힙 압력은 일반적으로 힙이 괜찮아 보이는데도 검색이 느리거나, 디스크 읽기가 많거나, 스왑 활동이 있거나, 재시작 후 캐시 적중률이 낮은 경우처럼 보입니다. 힙을 늘리면 첫 번째 경우에 도움이 될 수 있습니다. 두 번째 경우에는 상황을 악화시킬 수 있습니다.

대부분의 자체 관리 클러스터의 경우, 오래된 경험 법칙이 여전히 출발점으로 작동합니다. 힙을 시스템 RAM의 절반 이하로 설정하고 압축된 일반 객체 포인터 임계값 미만으로 유지하세요. 사람들은 종종 그 임계값을 "약 32GB"라고 인용합니다. 실제로 많은 운영자는 26-31GB 정도를 유지하는데, 정확한 컷오프는 JVM 및 런타임 레이아웃에 따라 달라지기 때문입니다. Elasticsearch는 시작 시 압축된 일반 객체 포인터가 활성화되었는지 여부를 기록합니다. 노드에 대한 진실의 근원으로 시작 로그를 취급하세요.

최신 Elasticsearch 릴리스에서는 자동 힙 크기 조정이 노드 역할과 사용 가능한 메모리를 기반으로 합리적인 값을 이미 설정할 수 있습니다. 이는 특히 소규모 클러스터와 표준 배포에 유용합니다. 노드에 비정상적인 워크로드(무거운 집계, 큰 매핑, 많은 샤드, 수집 파이프라인, 변환 작업, 머신 러닝 역할 또는 핫 검색과 높은 인덱싱 볼륨의 혼합)가 있을 때는 수동 튜닝이 여전히 중요합니다.

간단한 예를 들어보겠습니다. 인덱싱과 검색을 모두 처리하는 64GB 핫 데이터 노드가 있다고 가정해 보겠습니다. 30GB의 힙은 일반적인 출발점입니다. OS 페이지 캐시와 네이티브 메모리를 위해 대략 절반의 RAM을 남겨둡니다. 동일한 노드가 많은 작은 샤드와 높은 카디널리티 집계가 있는 로깅 클러스터의 일부인 경우에도 힙 압력이 여전히 발생할 수 있습니다. 해결책은 더 나은 샤드 설계 또는 매핑 정리일 수 있으며, 자동으로 40GB 힙으로 설정하는 것이 아닙니다. 압축된 포인터 임계값 위로 이동하면 객체 포인터 크기가 증가하고 효과적인 힙 효율성이 감소할 수 있습니다.

최소 및 최대 힙을 동일한 값으로 설정하세요. Elasticsearch는 트래픽을 처리하는 동안 힙 크기 조정에 시간을 소비해서는 안 됩니다.

-Xms30g
-Xmx30g

설치가 지원하는 경우 패키지된 jvm.options 파일을 직접 편집하는 대신 jvm.options.d/ 아래의 파일을 사용하세요. 패키지 설치의 경우 일반적으로 /etc/elasticsearch/jvm.options.d/heap.options와 같은 것을 의미합니다. Docker의 경우 지원되는 환경 변수 또는 마운트된 구성을 통해 힙 설정을 전달하세요. 동일한 역할을 가진 노드에 대해 설정을 일관되게 유지하되 모든 역할에 동일한 힙이 필요하다고 가정하지 마세요. 전용 마스터 후보 노드는 인덱스, 필드 또는 샤드가 너무 많아서 클러스터에 매우 큰 메타데이터가 없는 한 바쁜 데이터 노드보다 훨씬 적은 힙이 필요한 경우가 많습니다.

힙을 변경하기 전에 현재 동작의 스냅샷을 찍으세요. JVM 통계를 확인하세요:

GET _nodes/stats/jvm?filter_path=nodes.*.jvm.mem,nodes.*.jvm.gc

그런 다음 차단기와 fielddata를 확인하세요:

GET _nodes/stats/breaker,indices/fielddata?pretty

또한 샤드와 매핑을 확인하세요. 수천 개의 작은 샤드가 있는 클러스터는 데이터 볼륨이 크지 않더라도 오버헤드로 힙을 소모할 수 있습니다.

GET _cat/shards?v&bytes=gb
GET _cluster/stats?filter_path=indices.count,indices.shards,indices.mappings

증상이 헤드라인 숫자보다 더 중요합니다. 가비지 컬렉션이 빠르게 낮추면 버스트 중에 힙이 약 70-85%에 머무르는 것은 정상일 수 있습니다. 힙이 90%대까지 올라가고 그대로 유지되는 것은 다릅니다. 높은 비율 자체보다 오래된 세대 GC 일시 중지가 더 나쁩니다. GC가 실행될 때마다 검색 시간이 초과되면 사용자는 평균 힙 차트가 허용 가능해 보였는지 신경 쓰지 않습니다.

일반적인 프로덕션 실수는 잘못된 매핑에 대한 붕대로 힙을 사용하는 것입니다. fielddata: true로 분석된 text 필드를 정렬하거나 집계하면 많은 힙을 소비할 수 있습니다. 더 나은 수정은 일반적으로 keyword 하위 필드, 낮은 카디널리티 필드 또는 다른 집계 설계입니다. 또 다른 실수는 동적 매핑이 임의의 JSON 키에서 수천 개의 필드를 생성하도록 허용하는 것입니다. 그러면 힙이 매핑, 클러스터 상태 및 쿼리 구조로 사라집니다. 동적 필드가 운영 문제가 되기 전에 경계를 설정하세요.

집계는 특별한 주의가 필요합니다. 높은 카디널리티 필드에 대한 용어 집계는 큰 인메모리 구조를 만들 수 있습니다. 누군가가 user_id, session_id 또는 전체 URL로 긴 시간 범위에 걸쳐 그룹화하는 대시보드를 실행하면 일반 검색이 괜찮아 보여도 힙 압력이 급증할 수 있습니다. 더 작은 시간 창, 작업 세트를 좁히는 필터, 페이지 매김을 위한 composite 집계 또는 적절한 경우 사전 집계된 롤업을 사용하세요. 힙을 높이면 실패가 지연될 수 있지만 무제한 집계를 저렴하게 만들지는 않습니다.

인덱싱에는 자체 힙 패턴이 있습니다. 대량 요청은 일시적인 압력을 만듭니다. 매우 큰 대량 페이로드는 Elasticsearch가 한 번에 너무 많은 작업을 보유하도록 강제할 수 있습니다. 수집 중에 인덱싱 거부 또는 힙 급증이 나타나면 더 작은 대량 배치와 더 많은 클라이언트 측 동시성 제어를 시도해 보세요. 유용한 시작 범위는 종종 대량 요청당 몇 메가바이트이며, 실제 문서로 위쪽으로 테스트하세요. 올바른 값은 문서 크기, 수집 파이프라인, 복제본, 새로 고침 간격 및 스토리지 속도에 따라 다릅니다.

운영 체제를 무시하지 마세요. 스왑을 비활성화하거나 Elasticsearch 메모리가 스왑 아웃되지 않도록 호스트를 구성하세요. 스와핑은 JVM 일시 중지가 엄청나게 커지기 때문에 복구 가능한 메모리 문제를 긴 중단으로 바꿀 수 있습니다. bootstrap.memory_lock: true를 사용하는 경우 프로세스에 메모리를 잠글 수 있는 권한이 있는지 확인하고 설정이 작동했다고 가정하지 말고 시작 시 확인하세요.

힙을 변경한 후 프로덕션 클러스터에서 한 번에 하나의 노드를 다시 시작하고 다음 노드로 이동하기 전에 샤드 복구가 안정될 때까지 기다리세요. 적어도 하나의 정상 트래픽 주기 동안 검색 지연 시간, GC 일시 중지, 디스크 읽기 및 인덱싱 처리량을 관찰하세요. 조용한 시간에 좋아 보이는 변경 사항이 아침 대시보드 러시 동안 실패할 수 있습니다.

합리적인 튜닝 후에도 노드가 계속 힙 압력을 받으면 한 걸음 물러서서 힙이 무엇을 보유하고 있는지 물어보세요. 너무 많은 샤드, 너무 많은 필드, 텍스트의 fielddata, 과도한 집계, 무거운 스크립트 및 동일한 노드의 혼합 역할이 "Elasticsearch에 모든 RAM이 필요함"보다 더 일반적인 원인입니다. 가장 강력한 힙 튜닝 작업은 종종 더 작은 매핑, 더 적은 샤드, 더 나은 쿼리 제한 또는 전용 수집 계층으로 끝납니다.

힙 튜닝은 일회성 의식이 아닙니다. 용량 관리의 일부입니다. 데이터 볼륨이 증가하거나, 대시보드가 변경되거나, 새 팀이 더 넓은 문서를 보내기 시작하면 메모리 프로필도 변경됩니다. 힙 크기 조정을 지루하게 유지하세요: 측정하고, 한 가지를 변경하고, 안전하게 다시 시작하고, 실제 워크로드 데이터로 확인하세요.