일반적인 Elasticsearch 성능 병목 현상 문제 해결
인덱싱, 검색, 힙, 스토리지 및 샤드 설계에서 Elasticsearch 성능 병목 현상을 찾기 위한 실용적인 워크플로우입니다.
일반적인 Elasticsearch 성능 병목 현상 문제 해결
Elasticsearch 성능 병목 현상을 해결할 때는 첫 번째로 떠오르는 쉬운 이론을 거부하는 것이 가장 효과적입니다. 느린 대시보드는 잘못된 쿼리 때문일 수 있지만, 핫 샤드, 포화된 디스크, 힙 문제, 매핑 실수 또는 I/O를 두고 경쟁하는 복구 프로세스 때문일 수도 있습니다. 증거부터 시작한 다음 범위를 좁히세요.
저는 보통 문제를 세 부분으로 나눕니다: 무엇이 느린지, 어디서 느린지, 그리고 무엇이 변경되었는지입니다. "Elasticsearch가 느리다"는 실행 가능한 정보가 아닙니다. "logs-prod-*에 대한 검색 지연 시간이 어제 매핑 변경 후 두 데이터 노드에서 주로 두 배로 증가했습니다"라는 정보가 작업할 수 있는 출발점을 제공합니다.
성능 문제 진단
구체적인 솔루션을 살펴보기 전에 성능 문제를 진단하기 위한 도구와 방법을 갖추는 것이 필수적입니다. Elasticsearch는 이 과정에서 매우 유용한 여러 API와 메트릭을 제공합니다.
주요 도구 및 메트릭:
- 클러스터 상태 API (
_cluster/health): 클러스터 상태(녹색, 노란색, 빨간색), 노드 수, 샤드 수 및 보류 중인 작업에 대한 개요를 제공합니다. 보류 중인 작업 수가 많으면 인덱싱 또는 복구 문제를 나타낼 수 있습니다. - 노드 통계 API (
_nodes/stats): CPU 사용량, 메모리, 디스크 I/O, 네트워크 트래픽 및 JVM 힙 사용량을 포함한 각 노드의 상세 통계를 제공합니다. 리소스가 제한된 노드를 식별하는 데 중요합니다. - 인덱스 통계 API (
_stats): 인덱싱 속도, 검색 속도 및 캐시 사용량과 같은 개별 인덱스의 통계를 제공합니다. 문제가 있는 인덱스를 정확히 찾아내는 데 도움이 됩니다. - 슬로우 로그: Elasticsearch는 느린 인덱싱 및 검색 요청을 기록할 수 있습니다. 슬로우 로그 임계값은 인덱스 설정이므로, 전체 클러스터를 로그 생성기로 만들지 않고 하나의 시끄러운 인덱스에 적용할 수 있습니다.
- 인덱싱 슬로우 로그: 대량 쓰기가 일시 중지되거나 수집 지연 시간이 증가할 때 유용합니다.
- 검색 슬로우 로그: 지연 시간 차트가 아닌 실제 요청 패턴이 필요할 때 유용합니다.
- 모니터링 도구: Kibana의 모니터링 UI, Elasticsearch Exporter가 있는 Prometheus 또는 상용 APM 도구와 같은 솔루션은 심층 분석을 위한 대시보드와 과거 데이터를 제공합니다.
일반적인 병목 현상 및 해결 방법
1. 느린 인덱싱
느린 인덱싱은 네트워크 지연 시간, 디스크 I/O 병목 현상, 리소스 부족, 비효율적인 매핑 또는 최적이 아닌 대량 API 사용을 포함한 다양한 요인으로 인해 발생할 수 있습니다.
원인 및 해결 방법:
디스크 I/O 포화: Elasticsearch는 인덱싱을 위해 빠른 디스크 I/O에 크게 의존합니다. SSD를 적극 권장합니다.
- 진단:
_nodes/stats또는 OS 수준 도구를 사용하여 디스크 읽기/쓰기 IOPS 및 처리량을 모니터링합니다. 높은 큐 깊이를 찾으십시오. - 해결 방법: 더 빠른 스토리지(SSD)로 업그레이드하고, 샤드를 더 많은 노드에 분산시키거나, 노드당 I/O를 줄이기 위해 샤드 전략을 최적화합니다.
- 진단:
JVM 힙 압력: JVM 힙이 지속적으로 압력을 받으면 가비지 수집이 심각한 병목 현상이 되어 인덱싱을 포함한 모든 작업이 느려질 수 있습니다.
- 진단: Kibana 모니터링 또는
_nodes/stats에서 JVM 힙 사용량을 모니터링합니다. 힙 사용량이 높고 빈번하고 긴 가비지 수집 일시 중지는 위험 신호입니다. - 해결 방법: JVM 힙 크기를 늘리되(시스템 RAM의 50%를 초과하지 않고 30.5GB를 초과하지 않음), 문서 크기를 줄이기 위해 매핑을 최적화하거나, 부하를 분산하기 위해 노드를 추가합니다.
- 진단: Kibana 모니터링 또는
비효율적인 매핑: 지나치게 복잡한 매핑, 많은 새 필드가 생성되는 동적 매핑 또는 잘못된 데이터 유형은 인덱싱 오버헤드를 증가시킬 수 있습니다.
- 진단: 인덱스 매핑(
_mappingAPI)을 분석합니다. 중첩된 객체, 많은 수의 필드 또는 불필요하게 인덱싱된 필드를 찾으십시오. - 해결 방법: 적절한 데이터 유형으로 명시적 매핑을 정의합니다. 해당되는 경우
dynamic: false또는dynamic: strict를 사용합니다. 필수적이지 않으면 깊게 중첩된 구조를 피하십시오.
- 진단: 인덱스 매핑(
네트워크 지연 시간: 노드 간 또는 클라이언트와 클러스터 간의 높은 지연 시간은 대량 인덱싱 요청을 느리게 할 수 있습니다.
- 진단: 클라이언트/노드 간의 네트워크 지연 시간을 측정합니다. 대량 API 응답 시간을 분석합니다.
- 해결 방법: 클러스터 노드를 지연 시간이 짧은 사설 네트워크에 유지하고, 가능하면 대량 클라이언트를 클러스터 가까이에 배치하며, 불필요한 교차 리전 트래픽을 줄입니다. 요청 캐시 설정은 네트워크 지연 시간을 해결하지 못합니다.
최적이 아닌 대량 API 사용: 대량 요청 대신 개별 요청을 보내거나, 지나치게 크거나 작은 대량 요청을 보내는 것은 비효율적일 수 있습니다.
- 진단: 대량 인덱싱의 처리량을 모니터링합니다. 대량 요청의 크기를 분석합니다.
- 해결 방법: 모든 인덱싱 작업에 대량 API를 사용합니다. 대량 크기를 실험하여(일반적으로 대량 요청당 5-15MB가 좋은 시작점입니다) 처리량과 지연 시간 간의 최적 균형을 찾습니다. 대량 요청이 적절하게 배치되었는지 확인합니다.
트랜스로그 내구성:
index.translog.durability설정은 트랜잭션 로그가 디스크에 플러시되는 빈도를 제어합니다.request(기본값)는 더 안전하지만async에 비해 성능에 영향을 줄 수 있습니다.- 진단: 이것은 구성 설정입니다.
- 해결 방법: 최대 인덱싱 처리량을 위해
async내구성을 고려하십시오. 그러나 플러시 사이에 노드가 충돌할 경우 데이터 손실 위험이 증가한다는 점을 인식하십시오.
2. 느린 쿼리
쿼리 성능은 샤드 크기, 쿼리 복잡성, 캐싱 및 기본 데이터 구조의 효율성에 의해 영향을 받습니다.
원인 및 해결 방법:
큰 샤드: 너무 큰 샤드는 Elasticsearch가 더 많은 데이터를 검색하고 더 많은 세그먼트의 결과를 병합해야 하므로 쿼리를 느리게 할 수 있습니다.
- 진단:
_cat/shards또는_all/settings?pretty를 사용하여 샤드 크기를 확인합니다. - 해결 방법: 샤드 크기를 10GB에서 50GB 사이로 목표로 합니다. 더 작은 샤드로 새 인덱스에 데이터를 다시 인덱싱하거나 ILM(인덱스 수명 주기 관리)을 사용하여 시간이 지남에 따라 샤드 크기를 관리하는 것을 고려하십시오.
- 진단:
너무 많은 샤드: 과도하게 많은 수의 작은 샤드는 특히 검색 중에 클러스터에 높은 오버헤드를 초래할 수 있습니다. 각 샤드는 관리를 위한 리소스가 필요합니다.
- 진단:
_cat/shards를 사용하여 노드 및 인덱스당 총 샤드 수를 계산합니다. - 해결 방법: 가능하면 인덱스를 통합합니다. 데이터 모델을 최적화하여 인덱스 수와 총 샤드 수를 줄입니다. 시계열 데이터의 경우 ILM이 샤드 수를 관리하는 데 도움이 될 수 있습니다.
- 진단:
비효율적인 쿼리: 복잡한 쿼리, 과도한 스크립팅을 포함하는 쿼리, 용어 시작 부분의 와일드카드 검색 또는 정규식은 매우 리소스 집약적일 수 있습니다.
- 진단: 프로파일 API(
_search?profile=true)를 사용하여 쿼리 실행 시간을 분석하고 느린 부분을 식별합니다. 슬로우 로그를 분석합니다. - 해결 방법: 쿼리를 단순화합니다. 선행 와일드카드와 값비싼 정규식을 피하십시오. 가능하면 정확히 일치하는 항목에 대해
match대신term쿼리를 사용합니다. 자동 완성 제안을 위해search_as_you_type또는completionsuggester 사용을 고려하십시오. 필터 절을 최적화합니다(점수 매기지 않는 쿼리의 경우query컨텍스트 대신filter컨텍스트 사용).
- 진단: 프로파일 API(
캐싱 부족: 불충분하거나 비효율적인 캐싱은 반복적인 계산 및 데이터 검색으로 이어질 수 있습니다.
- 진단:
_nodes/stats/indices/query_cache및_nodes/stats/indices/request_cache를 사용하여 쿼리 캐시 및 요청 캐시의 적중률을 모니터링합니다. - 해결 방법: 적절한 캐싱이 활성화되었는지 확인합니다. 필터 캐시(쿼리 캐시의 일부)는 반복되는 필터 쿼리에 특히 중요합니다. 자주 실행되는 동일한 쿼리의 경우 요청 캐시를 활성화하는 것을 고려하십시오.
- 진단:
세그먼트 병합 오버헤드: Elasticsearch는 백그라운드에서 작은 세그먼트를 더 큰 세그먼트로 병합합니다. 이 프로세스는 I/O 및 CPU 리소스를 소비하며, 이는 실시간 쿼리 성능에 영향을 줄 수 있습니다.
- 진단:
_cat/segments를 사용하여 샤드당 세그먼트 수를 모니터링합니다. - 해결 방법: 병합 설정을 함부로 변경하지 마십시오. 대규모 백필 중에는 새로 고침 빈도를 줄이고, 대량 동시성을 제어하며, 병합 제한 및 디스크 I/O를 주시하십시오. 강제 병합은 일반적으로 활성 핫 인덱스가 아닌 읽기 전용 인덱스용입니다.
- 진단:
3. 리소스 경합 (CPU, 메모리, 네트워크)
리소스 경합은 인덱싱 및 쿼리 성능 저하 모두에서 나타날 수 있는 광범위한 범주입니다.
원인 및 해결 방법:
CPU 과부하: 높은 CPU 사용량은 복잡한 쿼리, 집약적인 집계, 너무 많은 인덱싱 작업 또는 과도한 가비지 수집으로 인해 발생할 수 있습니다.
- 진단: 노드별 CPU 사용량을 모니터링합니다(
_nodes/stats). 가장 많은 CPU를 소비하는 작업(예: 검색, 인덱싱, JVM GC)을 식별합니다. - 해결 방법: 쿼리 및 집계를 최적화합니다. 더 많은 노드에 부하를 분산합니다. CPU를 압도하는 경우 인덱싱 속도를 줄입니다. GC 오버헤드를 최소화하기 위해 적절한 JVM 힙 설정을 보장합니다.
- 진단: 노드별 CPU 사용량을 모니터링합니다(
메모리 문제 (JVM 힙 및 시스템 메모리): 불충분한 JVM 힙은 빈번한 GC로 이어집니다. 시스템 메모리가 부족하면 스와핑이 발생하여 성능이 크게 저하됩니다.
- 진단: 각 노드의 JVM 힙 사용량과 전체 시스템 메모리(RAM, 스왑)를 모니터링합니다.
- 해결 방법: 충분한 JVM 힙을 할당합니다(예: 시스템 RAM의 50%, 최대 30.5GB). 충분한 여유 시스템 메모리를 확보하여 스와핑을 방지합니다. 노드를 더 추가하거나 특정 역할(마스터, 데이터, 수집)에 전용 노드를 사용하는 것을 고려하십시오.
네트워크 병목 현상: 높은 네트워크 트래픽은 노드 간 통신, 복제 및 클라이언트 요청을 느리게 할 수 있습니다.
- 진단: 노드 및 클라이언트 간의 네트워크 대역폭 사용량과 지연 시간을 모니터링합니다.
- 해결 방법: 네트워크 인프라를 최적화합니다. 불필요한 데이터 전송을 줄입니다. 최적의 샤드 할당 및 복제 설정을 보장합니다.
디스크 I/O 포화: 인덱싱에서 언급했듯이 디스크에서 데이터를 읽을 때 쿼리 성능에도 영향을 미칩니다.
- 진단: 디스크 I/O 메트릭을 모니터링합니다.
- 해결 방법: 더 빠른 스토리지로 업그레이드하고, 더 많은 노드에 데이터를 분산시키거나, 읽는 데이터 양을 줄이기 위해 쿼리를 최적화합니다.
성능 튜닝을 위한 모범 사례
- 지속적으로 모니터링: 성능 튜닝은 지속적인 프로세스입니다. 클러스터 상태와 리소스 사용률을 정기적으로 모니터링하십시오.
- 매핑 최적화: 데이터에 맞게 명시적이고 효율적인 매핑을 정의합니다. 불필요한 필드나 인덱싱을 피하십시오.
- 샤드 전략: 최적의 샤드 크기(10-50GB)를 목표로 하고 너무 많거나 너무 적은 샤드를 피하십시오.
- 대량 API 사용: 인덱싱에는 대량 API를 사용하고, 독립적인 검색을 번들로 묶어야 할 때는 다중 검색 API를 사용하십시오.
- JVM 힙 튜닝: 충분한 힙을 할당하되, 과도하게 할당하지 마십시오. 스와핑을 피하십시오.
- 쿼리 성능 이해: 쿼리를 프로파일링하고, 단순화하며, 필터 컨텍스트를 활용하십시오.
- 캐싱 활용: 쿼리 및 요청 캐시가 효과적으로 사용되는지 확인하십시오.
- 하드웨어: 스토리지에 SSD를 사용하고 적절한 CPU와 RAM을 확보하십시오.
- 전용 노드: 워크로드를 격리하기 위해 마스터, 데이터 및 수집 역할에 전용 노드 사용을 고려하십시오.
- 인덱스 수명 주기 관리 (ILM): 시계열 데이터의 경우 ILM은 인덱스 관리, 샤드 롤오버 및 최종적으로 오래된 데이터 삭제에 필수적이며, 이는 샤드 수와 크기를 제어하는 데 도움이 됩니다.
병목 현상을 발견하면 이를 직접 해결하는 가장 작은 변경을 수행하십시오. 클러스터에 실제로 용량이 부족할 때 노드를 추가하십시오. 힙이 낭비될 때 매핑을 수정하십시오. 프로파일 출력이 비용이 많이 드는 절을 가리킬 때 쿼리를 다시 작성하십시오. 한 노드가 분산되어야 할 작업을 수행할 때 샤드 전략을 조정하십시오. 이러한 규율은 성능 작업이 관련 없는 튜닝 노브의 더미가 되는 것을 방지합니다.