top bar

글 목록

2015년 5월 9일 토요일

[Elasticsearch] Fielddata (2) - CircuitBreaker와 Limiting Memory Usage

1. Fielddata의 Memory 관련 이슈



이전 글에서, Fielddata는 모든 document의 field 값을 메모리에 적재한다고 하였다. 

여기서 언급 되지 않는 부분이 있는데, Elasticsearch 클러스터에는 새로운 document가 끊임 없이 색인 된다는 것이다. 그렇게되면 당연히 Fielddata의 크기도 점점 커질 것이고, 점점 더 많은 메모리를 사용할 것이다.

Elasticsearch는 알다시피 자바 환경에서 실행되는 어플리케이션이고, 할당된 메모리 즉 heap size가 존재한다. 이러한 환경에서, Fielddata의 크기가 할당된 heap size를 넘어서면 당연히 'Out Of Memory' 가 발생할 것이다.

이러한 이유로 인해, Elasticsearch에서는 'Circuit Breaker'(차단기) 라는 장치를 마련해 두고 있다.

2. Circuit Breaker와 Limiting Memory Usage



원문 - Limiting Memory Usage


* Circuit Breaker

circuit breaker는 이러한 메모리 이슈에 대응하기 위해 디자인된 일종의 예방 장치이다.
현재 수행하는 query가 얼마만큼 메모리를 필요로하는지 미리 계산하고 실제로 fielddata가
미리 설정된 메모리 상한이 넘어가도록 로딩되는지 검사한다. 이를 초과하게되면 해당 쿼리를 중지시키고
Exception을 발생시킨다.

한마디로 OOM이 발생하여 node가 죽어버리는 것을 방지하기 위한 장치인 셈이다.

Elasticsearch의 공식 문서에는 이에 대하여, OOM발생으로 인해 node가 뒤지는(?) 것보다 차라리 Exception이 발생하여 쿼리가 중지되는 편이 낫다(;;).. 라고 말하고 있다.

아래는 필자가 실무에서 실제로 만났던 CircuitBreakingException(이하 CBE)이다.


Circuit Breaker가 작동하는 메모리 사용 기준은 아래 api로 설정 할 수 있다.
$ curl -XPUT 'localhost:9200/_cluster/settings?pretty'
{
  "persistent" : {
    "indices.breaker.fielddata.limit" : "[percentage of heap size]"
  }
}
위 설정의 default 값은 "60%" 이다. 따라서 필자가 경험했던 이슈는 당시 Elasticsearch 각 node의 heap size가 8G였고, query에 사용되는 Fielddata의 크기가 8G의 60% 즉, 약 4.7G 을 넘었기 때문에 CBE가 발생한 것이었다.

위에서 언급했다 시피, CBE가 발생하면 query는 수행되지 않는다. 일단 필자가 취한 조치는 heap size의 크기를 16G로 늘리고, 'indice.breaker.fielddata.limit'의 percentage를 70%로 늘린 것이었다.

하지만 이것이 근본적인 해결책은 아니다. 왜냐하면 어찌됐든 새로운 document는 계속하여 색인될 것이고, 그에따라 Fielddata의 크기도 계속 커지게되면, 언젠간 heap size의 70%
도 넘어서게 될 것이기 때문이다. 그렇게되면 다시 CBE를 만나게 될것이다.

이를 해결 하는 방법은 Fielddata의 Cache size를 설정하여, 오래된 Field 값을 'Evict' 하는것이다. 이는 conf/elasticsearch.yml 파일에서 위의 설정처럼 heap size 대비 %로 아래와 같이 정의할 수 있다.
## conf/elasticsearch.yml

indices.fielddata.cache.size: [percentege of heap size]

이 값은 percentage값 뿐만 아니라 명시적인 용량 값(ex 5g 등..) 으로도 설정 할 수 있다. 이를 설정하지 않으면, Fielddata는 breaker가 작동하는 기준까지 계속하여 field값을 메모리에 로딩해 버린다. 

주의해야 할것은 'indices.fielddata.cache.size'값이 'indices.breaker.fielddata.limit'값보다 크면 안된다는 것이다. 그렇게 되어 버리면 fieldata에 로딩된 데이터를 evict 시키지 못하고 CBE가 발생해 버리기 때문이다.

위의 2가지 설정으로 CBE이슈는 해결할 수 있었다.

하지만 메모리 사용 이슈에 대한 가장 좋은 대응 방법은 이전 글에서 언급했다시피 node 확장을 통한 메모리 사용을 분산 시키는 것 이다. 물론 장비를 증설 해야 되므로 돈이 좀 들어가겠지만...

ES에는 메모리를 사용하는것 대신에 disk를 사용하는 'Doc Value' 라는 개념이 있다. disk에 여유가 있다면 사용해 볼만한 장치다. 나중포스트에 이 개념도 살펴 보도록 하겠다. (언제가될진 모르겠지만..)

댓글 1개: