미해결
ElasticSearch Essential
Compressed OOP 조건에 따른 ES Heap Size 제약
안녕하세요, 대용량 데이터 검색엔진 구축을 위해 Elasticsearch를 도입했습니다. 1. 개발환경 및 Spec 설명On-premise Kubernetes 환경에 Helm 배포를 통해 Master, Coordinating, Data Node 각각 4, 4, 10대로 Elasticsearch 클러스터를 구성했습니다.(HA 구성을 위해 Data Node는 모두 다른 Kubernetes Node에 배포되며, statefulSet을 통한 Rolling Update 방식입니다.)예상되는 클러스터 전체 Data Usage는 50TB 수준이고, primary shard와 replica shard의 개수는 각각 10과 1로 둘 예정입니다. 하나의 shard 용량은 10~20GB 수준으로 유지할 예정입니다. 현재는 초기 적재를 위해 replica shard 개수를 0으로 설정한 상황입니다.)pod container의 limit resource는 8core, 64Gi이며, ES_JAVA_OPTS 값으로는 -Xms30g -Xmx30g 옵션을 통해 Elasticsearch의 Heap Memory로는 30GB를 할당했습니다. 32Bit 포인터 관리 방식에서 object 그 자체가 아닌 object의 offset을 참조하는 Compressed OOP 사용을 위해, Elasticsearch의 Heap Size는 32GB를 권장하고 있습니다. 여기에 시작 주소를 0으로 두는 Zero-based 까지 고려하여 보수적으로 30GB를 사용했습니다.위와는 독립적인 권장 사항인 'JVM의 50%을 ES에 할당하라' 조건까지 고려하여 JVM Heapsize를 64Gi 로 두었습니다. 2. issue데이터 색인(bulk가 아닌 일반적인 PUT API) 중, kibana를 비롯하여 Elasticsearch 클러스터 전체에 503 에러가 발생했고 쿠버네티스 클러스터에 배포된 pod(Master, Coordinating Node 전부, 그리고 Data Node는 2대를 제외한 나머지 8개)가 restart 없이 죽었습니다. (원인은 CircuitBreaker입니다.)NAME READY STATUS RESTARTS AGE
edms-p01-srep01-coordinating-0 0/1 Running 0 37h
edms-p01-srep01-coordinating-1 0/1 Running 0 37h
edms-p01-srep01-coordinating-2 0/1 Running 0 37h
edms-p01-srep01-coordinating-3 0/1 Running 0 37h
edms-p01-srep01-data-0 0/1 Running 0 37h
edms-p01-srep01-data-1 0/1 Running 0 37h
edms-p01-srep01-data-2 1/1 Running 0 37h
edms-p01-srep01-data-3 0/1 Running 0 37h
edms-p01-srep01-data-4 0/1 Running 0 37h
edms-p01-srep01-data-5 0/1 Running 0 37h
edms-p01-srep01-data-6 1/1 Running 0 37h
edms-p01-srep01-data-7 0/1 Running 0 37h
edms-p01-srep01-data-8 0/1 Running 0 26h
edms-p01-srep01-data-9 0/1 Running 0 37h
edms-p01-srep01-es-exporter-8457b87fb7-wsshd 1/1 Running 0 39h
edms-p01-srep01-kb-84dcb6d7f7-gdhd9 0/1 Running 0 39h
edms-p01-srep01-master-0 0/1 Running 0 37h
edms-p01-srep01-master-1 0/1 Running 0 37h
edms-p01-srep01-master-2 0/1 Running 0 37h
edms-p01-srep01-master-3 0/1 Running 0 37h
Data Node의 경우 빈번한 Young GC, 그리고 Old GC가 발생했지만 점차 확보하는 Memory 양이 적어지다가 CircuitBreakingException이 발생했습니다.Master와 Coordinating Node는 Old GC 없이 Young GC만으로 heap size가 잘 관리되다가 모든 Data Node 메모리 부하가 심해지니 Pod가 죽었는데, 유추하기로는 처리되지 못한 색인 데이터의 transport가 loop 되다가 Master/Coordinating 메모리에도 영향을 준 것으로 보입니다. CircuitBreakingException이 발생 전의 한 Data Node의 stats은 아래와 같습니다. (GET _nodes/stats)
"mem" : {
"heap_used_in_bytes" : 28558120848,
"heap_used_percent" : 88,
"heap_committed_in_bytes" : 32212254720,
"heap_max_in_bytes" : 32212254720,
"non_heap_used_in_bytes" : 191720344,
"non_heap_committed_in_bytes" : 201515008,
"pools" : {
"young" : {
"used_in_bytes" : 771751936,
"max_in_bytes" : 0,
"peak_used_in_bytes" : 19243466752,
"peak_max_in_bytes" : 0
},
"old" : {
"used_in_bytes" : 27784679400,
"max_in_bytes" : 32212254720,
"peak_used_in_bytes" : 32129130920,
"peak_max_in_bytes" : 32212254720
},
"survivor" : {
"used_in_bytes" : 1689512,
"max_in_bytes" : 0,
"peak_used_in_bytes" : 1520169584,
"peak_max_in_bytes" : 0
}
}
},
...
"gc" : {
"collectors" : {
"young" : {
"collection_count" : 226,
"collection_time_in_millis" : 15603
},
"old" : {
"collection_count" : 1,
"collection_time_in_millis" : 6322
}
}
} 3. 의문점Data node 역할을 담당하는 pod가 죽은 것은 그럴 수 있다 쳐도 색인과 관련 없는 Coordinating/Master Node 역할의 pod에까지 영향을 미치는 이유는 무엇인가요?(위의 pod metric을 살펴보아도 OOM과는 전혀 거리가 멀어보이긴 합니다만) Elasticsearch가 분산시스템이지만 위와 같이 Kubernetes 노드에 문제가 없는 상태에서 pod만 죽어버리니 고가용성이 무색해지는군요... 앞서 말씀드린 것처럼 색인 데이터의 transport 내부 동작이 영향을 미쳤을까요?위와 같은 CircuitBreakingException에 대응하는 방법에는 ES_JAVA_OPT의 Heap Memory 용량을 증설하거나, 클러스터 세팅 indices.breaker.total.limit 값은 이미 95%입니다. (indices.breaker.total.use_real_memory가 true 이므로) 이때, 이미 Heap이 30GB라면, Compressed OOP의 조건인 32GB를 넘는 수준의 ES_JAVA_OPTS 설정을 시도하려면 어느 정도로 높게 하는게 좋을지 고견을 여쭙습니다.(Container의 jvm memory 자체에는 큰 제약이 없는 개발환경입니다. 즉, 128GB, 256GB처럼 높은 수준의 resources.limit 설정도 가능합니다.)