ELK

[Elasticsearch] Circuit breaker 원인과 해결 방법

정윤재 2023. 5. 3. 00:29

1. Circuit breaker 란


ElasticSearch 에서 OutOfMemory 발생을 방지하기 위해 사용하는 기능
좀 더 상세히 설명하면 elasticsearch 에서는 jvm의 OutOfMemory 가 발생하여
node 가 다운되어 서비스가 아예 안되는 상황을 막기 위해  memory 사용량이
특정 임계치이상 올라가면 request 를 아예 안받아 버리는(prevent) 안전장치
기능이 존재 합니다.

2. Circuit breaker 의 종류

2-1. parent circuit breaker
 서로 다른 유형의 circuit breaker에서 사용되는 모든 메모리의 합계로 인해 발생
 
2-2. request circuit breaker
 검색을 통해 요청별 데이터 구조(예: 요청 중 집계 계산에 사용되는 메모리)가 특정 메모리 양을 초과하는 것을 방지할 수 있습니다

2-3. in flight requests circuit breaker
 검색을 통해 전송 또는 HTTP 수준에서 현재 활성 상태인 모든 수신 요청의 메모리 사용량이 노드의 특정 메모리 양을 초과하지 
 않도록 제한할 수 있습니다. 메모리 사용량은 요청 자체의 콘텐츠 길이를 기반으로 합니다.
 
2-4. accounting requests circuit breaker
 검색을 통해 요청이 완료될 때 해제되지 않는 메모리에 저장된 항목의 메모리 사용량을 제한할 수 있습니다. 
 여기에는 루씬 세그먼트 메모리와 같은 것들이 포함됩니다
 
2-5. Script compilation circuit breaker
 이전의 메모리 기반 circuit breaker 와 약간 다르게 일정 기간 내 인라인 스크립트 컴파일 수를 제한합니다
 
2-6. Regex circuit breaker
 정규식을 잘못 작성하면 클러스터 안정성과 성능이 저하될 수 있습니다. 정규식 circuit breaker 는 스크립트에서 
 정규식의 사용과 복잡성을 제한합니다.
 
각 항목들에 대한 상세 설명은 
https://www.elastic.co/guide/en/elasticsearch/reference/8.6/circuit-breaker.html
을 참고 하면 됩니다.

3. Circuit breaker 발생 시 로그


elasticsearch 의 node 안의 로그에서 

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]


와 같이 오류 메시지가 발생합니다.

해당 에러 메시지 내용은 
https://www.elastic.co/guide/en/elasticsearch/reference/8.6/circuit-breaker-errors.html#diagnose-circuit-breaker-errors
을 참고 하시면 됩니다.

4. Circuit breaker 발생 시 영향도


Elasticsearch 에서는 문제가 되는 요청을 계속 호출할 것이므로 data node, client node(cordinating node) 등에서
- 계속 Circuit breaker 가 발생하여 hang 과 같은 현상이 발생 할수 있다.
- 위의 현상에 따른 영향으로 kibana process 가 kill 될 수 있다.

5. 조치 방법


elastic 의 공식 guide 에선 
- jvm 에 대한 압력을 약화시켜라 
  https://www.elastic.co/guide/en/elasticsearch/reference/8.6/high-jvm-memory-pressure.html 참고
- fielddata 에 대해 text 를 피해라
- fieldata cache 를 삭제 해라
등의 하나마나한 얘기를 하고 있지만 가장 현실적인건 역시 jvm 메모리 증설입니다. (jvm 에 대한 압력을 약화시켜라 부분의 마지막 부분에 있습니다.)
오류 부분을 보면 
5-1. ~CircuitBreakingException: [parent] Data too large ~~ 를 잘 보면 parent 라는 단어처럼 
어떤 Circuit breaker 가 발생 했는지 확인 할수 있습니다.

5-2. kibana 의 dev tools 에서
GET /_cluster/settings?include_defaults=true 
를 호출 해서 default 설정 값들도 다 조회 해 봅니다.

GET _nodes/stats/breaker 를 실행 해서 에러 메시지와 대조를 해 봅니다.
결과 예시)

"breakers" : {
     "request" : {
       "limit_size_in_bytes" : 20574004838,
       "limit_size" : "19.1gb",
       "estimated_size_in_bytes" : 0,
       "estimated_size" : "0b",
       "overhead" : 1.0,
       "tripped" : 0
     },
     "fielddata" : {
       "limit_size_in_bytes" : 13716003225,
       "limit_size" : "12.7gb",
       "estimated_size_in_bytes" : 0,
       "estimated_size" : "0b",
       "overhead" : 1.03,
       "tripped" : 0
     },
     "in_flight_requests" : {
       "limit_size_in_bytes" : 34290008064,
       "limit_size" : "31.9gb",
       "estimated_size_in_bytes" : 6254164,
       "estimated_size" : "5.9mb",
       "overhead" : 2.0,
       "tripped" : 0
     },
     "accounting" : {
       "limit_size_in_bytes" : 34290008064,
       "limit_size" : "31.9gb",
       "estimated_size_in_bytes" : 282771278,
       "estimated_size" : "269.6mb",
       "overhead" : 1.0,
       "tripped" : 0
     },
     "parent" : {
       "limit_size_in_bytes" : 32575507660,
       "limit_size" : "30.3gb",
       "estimated_size_in_bytes" : 13431618584,
       "estimated_size" : "12.5gb",
       "overhead" : 1.0,
       "tripped" : 0
     }
   }



예를 들어 아까 메시지가 [parent] 부분이 있었기 때문에 parent 의 limit_size 와 node 의 jvm에 설정된
Xmx 값을 비교해보면 됩니다. 
위의 GET /_cluster/settings?include_defaults=true  명령에서 indices.breaker.total.limit 라는
값으로 jvm 의 Xmx 대비 몇%다라는 걸 확인 할 수 있으므로 어느 노드에서 발생하는지 확인이 가능합니다.

5-3. (선택 1) kibana 의 dev tools 를 사용하여 임계치 관련 항목의 설정값을 수정합니다.


PUT /_cluster/settings
{
"transient" : {
"indices.breaker.total.limit" : "80%"
}
}



또는

PUT /_cluster/settings
{
"persistent" : {
"indices.breaker.total.limit" : "80%"
}
}


*  transient 는 재기동 하면 설정값 삭제됨, persistent 는 재기동 후에도 해당 설정 적용 및 존재

5-4. (선택 2) 5-2 에서 확인 된 문제의 node 에 대한 JVM 의 Xmx 값 변경(증설)
당연하게도 가장 강력하고 빠른 해결책은 5-4 (JVM heap memory 증설) 이며 5-2에서 문제의 원인이 되는 elasticsearh node 를 찾는게 가장 중요합니다.