Elasticsearch 메모리 관리 및 문제 해결
.jpg)
Elastic Cloud가 통합 가시성, 보안 및 검색과 같은 솔루션을 제공하면서 Elastic Cloud 사용자는 전담 운영 팀을 넘어 데이터 엔지니어, 보안 팀 및 컨설턴트까지 확대되었습니다. Elastic 지원 담당자로서, 저는 다양한 사용자 및 사용 사례와 소통하는 일을 즐기고 있습니다.
사용자층이 넓어지면서 리소스 할당 관리, 특히 할당 상태 문제 해결 및 서킷 브레이커 방지에 관한 질문을 더 많이 받고 있습니다. 이해합니다! 저도 Elasticsearch를 처음 사용했을 때 같은 질문을 했습니다. Java 힙과 시계열 데이터베이스 샤드를 관리하고 자체 인프라를 확장하는 방법을 처음 접한 경험이었습니다.
Elastic에 합류했을 때는 문서뿐 아니라 블로그와 튜토리얼도 제공되어 빠르게 온보딩할 수 있다는 점이 좋았습니다. 하지만 처음 한 달 동안에는 이론적 지식을 사용자가 제 티켓 대기열로 보내는 오류와 연관 짓는 데 어려움을 겪었습니다. 결국 다른 지원 담당자들과 마찬가지로 보고된 오류의 상당수가 할당 문제의 증상일 뿐이며, 약 7개의 동일한 링크를 통해 사용자가 리소스 할당을 성공적으로 관리하는 데 필요한 지식을 갖출 수 있다는 사실을 알게 되었습니다.
지원 담당자의 관점에서 사용자에게 보내는 주요 할당 관리 이론 링크, 자주 확인되는 주요 증상 및 리소스 할당 문제를 해결하기 위해 사용자가 구성을 업데이트하도록 안내하는 위치를 살펴보겠습니다.
이론
Java 애플리케이션인 Elasticsearch는 시스템의 물리 메모리에서 일정량의 논리 메모리(힙)를 할당받아야 합니다. 이 값은 물리적 RAM의 최대 절반으로 하되, 상한은 32GB입니다. 힙 사용량을 더 높게 설정하는 것은 일반적으로 비용이 많이 드는 쿼리와 더 큰 데이터 저장 공간에 대응하기 위한 것입니다. 상위 서킷 브레이커의 기본값은 95%이지만, 지속적으로 85%에 도달하면 리소스를 확장하는 것이 좋습니다.
자세한 내용은 다음 개요 문서를 참고하세요.
구성
별도 설정 없이 Elasticsearch의 기본 설정은 노드 역할과 총 메모리를 기준으로 JVM 힙 크기를 자동 설정합니다. 하지만 필요에 따라 다음 세 가지 방법으로 직접 구성할 수 있습니다.
1. 로컬 Elasticsearch 파일의 config > jvm.options 파일에서 직접 구성
## JVM configuration
################################################################
## IMPORTANT: JVM heap size
################################################################
…
# Xms represents the initial size of total heap space
# Xmx represents the maximum size of total heap space
-Xms4g
-Xmx4g2. docker-compose에서 Elasticsearch 환경 변수로 구성
version: '2.2'
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.12.0
environment:
- node.name=es01
- cluster.name=es
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms4g -Xmx4g"
- discovery.type=single-node
ulimits:
memlock:
soft: -1
hard: -1
ports:
- 9200:92003. Elastic Cloud Hosted > Deployment(배포) > Edit(편집) 보기에서 구성 참고: 드롭다운에서 물리 메모리를 할당하며, 이 중 약 절반이 힙에 할당됩니다.

문제 해결
현재 클러스터에서 성능 문제가 발생하고 있다면, 대부분 다음과 같은 일반적인 원인으로 귀결됩니다.
- 구성 문제: 크기가 부족한 마스터 노드, ILM 정책 부재
- 볼륨으로 인한 문제: 높은 요청 속도/부하, 비용이 많이 드는 쿼리/쓰기의 중첩
할당 상태
데이터 인덱스는 하위 샤드에 저장되며, 샤드는 유지 관리와 검색/쓰기 요청 중에 힙을 사용합니다. 샤드 크기는 50GB를 넘지 않아야 합니다. 앞서 살펴본 두 영역 전체에 물리 메모리 8GB가 있는 Elastic Cloud Hosted 예시(총 2개 노드가 할당됨)에 다음 _cat/allocation 예시를 적용해 보겠습니다.
GET /_cat/allocation?v=true&h=shards,node
shards node
41 instance-0000000001
41 instance-0000000000그리고 _cluster/health도 살펴보겠습니다.
GET /_cluster/health?filter_path=status,*_shards
{
"status": "green",
"unassigned_shards": 0,
"initializing_shards": 0,
"active_primary_shards": 41,
"relocating_shards": 0,
"active_shards": 82,
"delayed_unassigned_shards": 0
}active_shards 또는 active_primary_shards 외의 샤드 항목 중 0보다 큰 값이 보고되면 성능 문제의 원인을 찾은 것입니다.
이 문제가 보고되는 가장 일반적인 경우는 unassigned_shards>0입니다. 이러한 샤드가 기본 샤드이면 클러스터에서 status:red가 보고되고, 복제본만 해당하면 status:yellow가 보고됩니다. (이것이 인덱스에 복제본을 설정하는 것이 중요한 이유입니다. 클러스터에 문제가 발생해도 데이터 손실을 겪는 대신 복구할 수 있기 때문입니다.) 할당되지 않은 샤드가 하나인 status:yellow 상태라고 가정해 보겠습니다. 어떤 인덱스 샤드에 문제가 있는지 조사하려면 _cat/shards를 살펴봅니다.
GET _cat/shards?v=true&s=state
index shard prirep state docs store ip node
logs 0 p STARTED 2 10.1kb 10.42.255.40 instance-0000000001
logs 0 r UNASSIGNED
kibana_sample_data_logs 0 p STARTED 14074 10.6mb 10.42.255.40 instance-0000000001
.kibana_1 0 p STARTED 2261 3.8mb 10.42.255.40 instance-0000000001따라서 이는 할당되지 않은 복제본 샤드가 있는 비시스템 logs 인덱스의 경우입니다. _cluster/allocation/explain을 실행하여 무엇이 문제를 일으키는지 살펴보겠습니다. (프로 팁: 지원팀에 에스컬레이션하면 바로 이 작업을 수행합니다.)
GET _cluster/allocation/explain?pretty&filter_path=index,node_allocation_decisions.node_name,node_allocation_decisions.deciders.*
{ "index": "logs",
"node_allocation_decisions": [{
"node_name": "instance-0000000005",
"deciders": [{
"decider": "data_tier",
"decision": "NO",
"explanation": "node does not match any index setting [index.routing.allocation.include._tier] tier filters [data_hot]"
}]}]}이 오류 메시지는 인덱스 수명 주기 관리(ILM) 정책의 일부인 data_hot을 가리키며, 현재 인덱스 설정과 ILM 정책이 일치하지 않음을 나타냅니다. 이 경우 오류의 원인은 핫-웜 노드를 지정하지 않은 상태에서 핫-웜 ILM 정책을 설정했기 때문입니다. (무언가 반드시 실패하도록 해야 했기에, 여러분에게 오류 예시를 보여 주기 위해 제가 일부러 오류를 발생시킨 것입니다. 해결 방법을 단계별로 설명하는 이 문제 해결 예시 동영상에서 자세한 내용을 확인하세요.)
할당되지 않은 샤드가 없을 때 이 명령을 실행하면 보고할 문제가 없으므로, 설명할 할당되지 않은 샤드를 찾을 수 없다는 내용의 400 오류가 발생합니다. 논리적 원인이 아닌 경우(예: 할당 중 노드가 클러스터를 떠나는 일시적인 네트워크 오류가 발생한 경우) Elastic의 유용한 _cluster/reroute를 사용할 수 있습니다.
POST /_cluster/reroute사용자 지정 없이 이 요청을 실행하면 현재 state:UNASSIGNED 상태인 모든 샤드를 할당하려고 시도하는 비동기 백그라운드 프로세스가 시작됩니다. (저처럼 이 작업이 완료되기를 기다리지 않고 개발팀에 연락하지는 마세요. 저는 이 작업이 즉시 끝날 것이라고 생각했는데, 공교롭게도 개발팀에 에스컬레이션했을 무렵에는 이미 문제가 사라져 있어 아무 문제도 없다는 답변을 받았습니다.) 자세한 내용은 할당 상태 모니터링에 관한 이 문제 해결 동영상을 참조하세요.
서킷 브레이커
힙 할당을 한도까지 사용하면 클러스터 요청이 시간 초과되거나 오류가 발생할 수 있으며, 클러스터에서 서킷 브레이커 예외가 발생하는 경우가 많습니다. 서킷 브레이커 오류가 발생하면 다음과 같은 elasticsearch.log 이벤트가 기록됩니다.
Caused by: org.elasticsearch.common.breaker.CircuitBreakingException: [parent] Data too large, data for [<transport_request>] would be [num/numGB], which is larger than the limit of [num/numGB], usages [request=0/0b, fielddata=num/numKB, in_flight_requests=num/numGB, accounting=num/numGB]조사하려면 _cat/nodes를 확인하는 등의 방법으로 heap.percent를 살펴보세요.
GET /_cat/nodes?v=true&h=name,node*,heap*
# heap = JVM (logical memory reserved for heap)
# ram = physical memory
name node.role heap.current heap.percent heap.max
tiebreaker-0000000002 mv 119.8mb 23 508mb
instance-0000000001 himrst 1.8gb 48 3.9gb
instance-0000000000 himrst 2.8gb 73 3.9gb또는 이전에 활성화한 경우 Kibana > Stack Monitoring(스택 모니터링)으로 이동하세요.

메모리 서킷 브레이커에 도달하고 있음을 확인했다면, 조사할 여유를 확보하기 위해 일시적으로 힙을 늘리는 방법을 고려해야 합니다. 근본 원인을 조사할 때는 감사 로깅, 슬로우 로깅, clusterlogs 또는 elasticsearch.log에서 그 전에 연속적으로 발생한 이벤트를 살펴보세요. 다음 항목을 찾아야 합니다.
- 비용이 많이 드는 쿼리, 특히:
- 버킷 수가 많은 집계
- 검색은 검색 크기 또는 버킷 차원에 따라 쿼리를 실행하기 전에 힙의 일정 부분을 임시로 할당한다는 사실을 알았을 때, 저는 10,000,000으로 설정한 제 판단이 정말 어리석었다고 느꼈습니다. 그렇게 설정한 것이 운영 팀을 몹시 불안하게 만들었던 것입니다.
- 최적화되지 않은 매핑
- 두 번째로 제가 어리석었다고 느낀 이유는 계층형 보고가 평면화된 데이터보다 검색 성능이 더 좋을 것이라고 생각했던 것입니다(실제로는 그렇지 않습니다).
- 버킷 수가 많은 집계
- 요청량/속도: 일반적으로 배치 또는 비동기 쿼리
확장할 시점
서킷 브레이커에 도달한 것이 처음이 아니거나 이것이 지속적인 문제가 될 것으로 예상된다면(예: 지속적으로 85%에 도달하여 리소스 확장을 검토해야 하는 경우), 장기적인 힙 지표로서 JVM 메모리 압력을 자세히 살펴봐야 합니다. Elastic Cloud Hosted > Deployment(배포)에서 이를 확인할 수 있습니다.

또는 _nodes/stats에서 이를 계산하실 수 있습니다.
GET /_nodes/stats?filter_path=nodes.*.jvm.mem.pools.old
{"nodes": { "node_id": { "jvm": { "mem": { "pools": { "old": {
"max_in_bytes": 532676608,
"peak_max_in_bytes": 532676608,
"peak_used_in_bytes": 104465408,
"used_in_bytes": 104465408
}}}}}}}위치:
JVM Memory Pressure = used_in_bytes / max_in_bytes이로 인해 발생할 수 있는 증상은 elasticsearch.log의 가비지 컬렉터(gc) 이벤트에서 발생하는 빈도가 높고 지속 시간이 길다는 것입니다.
[timestamp_short_interval_from_last][INFO ][o.e.m.j.JvmGcMonitorService] [node_id] [gc][number] overhead, spent [21s] collecting in the last [40s]이 상황이 확인되면 클러스터를 확장하거나 클러스터에 가해지는 부하를 줄이는 방안을 살펴봐야 합니다. 조사/고려해야 할 사항은 다음과 같습니다.
저희가 돕겠습니다
자! 제가 Elastic 지원 업무에서 접하는 사례를 기준으로 하면, 할당되지 않은 샤드, 불균형한 샤드-힙, 서킷 브레이커, 높은 가비지 컬렉션 및 할당 오류가 가장 일반적인 사용자 티켓의 주요 내용입니다. 모두 리소스 할당 관리라는 핵심 주제와 관련된 증상입니다. 이제 관련 이론과 해결 단계도 알게 되셨기를 바랍니다.
그래도 문제 해결에 어려움을 겪고 있다면 언제든지 문의해 주세요. Elastic이 기꺼이 도와드리겠습니다! 다음 채널로 문의할 수 있습니다.
운영 담당자가 아니더라도 Elastic Stack의 리소스 할당을 직접 관리할 수 있기를 바랍니다(물론 운영 담당자분들도 응원합니다)!
추가 리소스:
최초 게시일: 2021년 4월 27일, 업데이트일: 2024년 11월 5일.
이 게시물에서 설명된 모든 기능이나 성능의 출시와 일정은 Elastic의 단독 재량에 따라 결정됩니다. 현재 제공되지 않는 기능이나 성능은 예정된 시간에 출시되지 않을 수도 있으며 아예 제공되지 않을 수도 있습니다.