🧄

ES의 CPU 사용량 100% 문제 해결

상황

Elasticsearch(ES)의 CPU 사용량이 100%로 급격하게 증가하는 문제가 발생했다. 할인 정보를 읽어 할인 가격을 주기적으로 업데이트하는 작업이 있다. 할인 정보 데이터를 ES로부터 읽을 때, CPU 사용량이 100%까지 증가하고 있었다. 왜 그럴까.

할인 정보 데이터의 볼륨이 작지 않았다. 그리고 특정 기간(time window) 안의 데이터를 조회하는 범위(range) 조회를 하고 있었다. ES는 인덱싱만 한다면 어떠한 속성으로도 조회가 가능하니 10분 단위의 범위 조회가 부담이 되지 않을 것으로 생각했다.

문제

문제의 원인을 밝히긴 위해서 실제 애플리케이션이 어떤 쿼리를 이용해 ES를 조회하는지 알아봐야 했다. 로컬에서 디버깅을 통해 쿼리빌더에서부터 실제 쿼리가 만들어지고 호출하는 부분까지 파악했다. 애플리케이션에 사용한 쿼리는 spring-data-elasticsearch:3.2.12.RELEASE 에 있는 NavtiveSearchQueryBuilder 다. 이 쿼리 빌더에서 withFilter  함수를 이용해 조회할 데이터의 조건을 명시했다. 필터를 사용하여 RDBMS처럼의 where 조건을 기대했다. 실제 withFilter 가 쿼리로 변환되면 post_filter 를 사용하는데, ES를 처음 경험해본 나는 post_filter 가 where 과 같겠지라고 생각했다. 개발하면 항상 느끼는데, 어떤 한 부분에 대해서 명확히 하지 않고 지레짐작으로 넘어가면 그 부분에서 문제가 발생한다는 것이다. 마치 머피의 법칙처럼 말이다. 

해결

이번에도 post_filter 를 사용하는 부분이 문제였다. 성능 측면에서 post_filter 와 filter 는 큰 차이가 있다. 참고 자료를 보면 더 자세히 알 수 있지만, 핵심은 post_filter 는 필터를 통해 어떠한 성능 이점을 가질 수 없다는 점이다. 이후 withFilter 를 제거하고 따로 bool query를 활용하여 필터를 만들어 withQuery 를 사용하도록 변경했다. 결과적으로 CPU 사용량이 100%에서 40%로 줄어 들었다.

반성

사실 문제가 발생하기 전에 라이브러리가 post_filter 를 사용하는지 알았다. 그러나 라이브러리에 대한 믿음을 가지고 문서를 정독하기 않고 코드를 유심히 살펴보지도 않았다. filter 와 post_filter 가 왜 다른지에 대해서 조금만 찾아봤다면 문제 상황을 만들지 않았을 것이다. 괜찮겠거니하며 넘겼던 나를 반성한다.