서론

우리 팀에서는 검색 기능에 Elasticsearch를 사용한다. 배포 중 새 인덱스가 추가되거나 맵핑 변경이 포함된 경우에는 MySQL 데이터와의 동기화하는 작업이 필요한데, 시간이 오래 걸리는 문제가 있었다. 기존 작업은 새 인덱스를 만든 다음 모든 공고에 대해서 각 MySQL을 조회하여 특정 개수의 데이터를 모은 뒤 Elasticsearch 서버에 bulk API를 요청하고 있다. 마지막에 고정된 인덱스 별칭만 바꿔치기 한다.

 

주된 병목 원인인 MySQL 조회 쿼리 N+1 문제를 해결하여 실행시간을 33분에서 13분대로 개선했는데, Elasticsearch 서버의 지표를 모니터링하던 중 특이 사항이 있었다.

CPU 스로틀

Cgroup CFS Throttle Count가 벌크 인덱스 실행시간 내내 7~8을 유지했다.

  • cgroup(리소스 제한 정책)에 의해 CPU 사용이 강제로 차단된 횟수

예를 들어 이번 주기(100ms)가 시작된 지 겨우 30ms(물리적 시간) 만에, 모든 코어가 열일해서 할당된 Quota(200ms, CPU가 일한 시간, 여러 코어의 Sum)를 다 써버리면 커널은 이 컨테이너는 이번 주기 할당량을 다 썼다고 판단하고, 남은 70ms 동안 해당 컨테이너의 모든 프로세스를 Ready Queue에서 빼버린다. (할당량을 관리하는 것은 다른 컨테이너가 영향을 받지 않도록 하는 것 같다)

데이터 저장인데 왜 CPU가 문제일까 ?

Bulk 요청이 들어오면 CPU는 다음의 일을 한다.

  • JSON 파싱 및 역직렬화
  • 텍스트를 토큰화하고, 형태소 분석을 하고, 역색인구조를 만듬
  • 세그먼트 파일로 저장하기 위해 데이터를 압축

이 때, bulk 옵션으로 refresh(즉시 검색 결과에 반영)를 설정하면 아래 부하가 추가된다.

  • CPU는 메모리에 임시로 모아둔 데이터(In-memory buffer)를 꺼내어 리눅스 시스템의 파일 형태인 Lucene Segment로 만듬
  • 이 과정에서 데이터 구조를 재배열하고, 검색에 최적화된 포맷으로 변경하는 연산이 필요

해결 방법

기존 bulk API 요청마다 refresh를 하고 있었지만 굳이 그럴 필요가 없었기에, 비활성화 설정한 후 모든 bulk가 완료되고 나서 1회 Refresh 및 설정을 원상복구했다. 이로써 인덱싱 진행 중 CPU 스로틀은 1 정도로 감소했으며, CPU사용량도 100% 에서 74%로 줄었다.

 

 

 

참고

https://www.elastic.co/docs/manage-data/data-store/near-real-time-search

 

Near real-time search | Elastic Docs

When a document is stored in Elasticsearch, it is indexed and fully searchable in near real-time--within 1 second. What defines near real-time search?...

www.elastic.co

 

https://www.elastic.co/docs/deploy-manage/production-guidance/optimize-performance/indexing-speed

 

Tune for indexing speed | Elastic Docs

Elasticsearch offers a wide range of indexing performance optimizations, which are especially useful for high-throughput ingestion workloads. This page...

www.elastic.co

 

https://www.elastic.co/docs/reference/elasticsearch/index-settings/merge

 

Merge settings | Reference

A shard in Elasticsearch is a Lucene index, and a Lucene index is broken down into segments. Segments are internal storage elements in the index where...

www.elastic.co

 

https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-refresh

 

Refresh an index | Elasticsearch API documentation

All methods and paths for this operation: POST /_refresh GET /_refresh POST ...

www.elastic.co

Refreshes are resource-intensive. To ensure good cluster performance, it's recommended to wait for Elasticsearch's periodic refresh rather than performing an explicit refresh when possible.

+ Recent posts