느린 Elasticsearch 검색 쿼리 진단 및 해결

느린 Elasticsearch 검색으로 어려움을 겪고 계신가요? 이 포괄적인 가이드는 비효율적인 쿼리 및 매핑 문제부터 하드웨어 한계에 이르기까지 일반적인 성능 병목 현상을 찾아내는 데 도움을 줍니다. Elasticsearch의 내장 도구를 사용하여 느린 쿼리를 진단하고, 더 빠르고 응답성이 좋은 검색 결과를 위한 실행 가능한 해결책을 구현하는 방법을 배우세요. 실용적인 팁과 모범 사례를 통해 클러스터를 최고의 성능으로 최적화하세요.

느린 Elasticsearch 검색 쿼리 진단 및 수정

느린 Elasticsearch 검색은 일반적으로 광범위한 쿼리, 비용이 많이 드는 집계, 매핑 선택, 샤드 레이아웃 또는 클러스터의 리소스 압박으로 인해 발생합니다. 인덱스가 성장한 후 검색 API가 시간 초과되거나 지연 시간이 급증하는 경우 쿼리, 인덱스 또는 클러스터 중 어느 부분이 과도한 작업을 수행하고 있는지 식별해야 합니다.

느린 로그와 프로필 API를 사용하여 비용이 많이 드는 부분을 찾은 다음, 증거에 따라 쿼리, 매핑, 샤드 전략 또는 하드웨어를 조정하세요.

느린 Elasticsearch 검색의 일반적인 원인

느린 검색 쿼리에는 여러 요인이 기여할 수 있습니다. 효과적인 문제 해결을 위해서는 환경에서 특정 원인을 식별하는 것이 중요합니다.

1. 비효율적인 쿼리

쿼리 설계는 검색 성능에 가장 직접적인 영향을 미치는 경우가 많습니다. 복잡하거나 잘못 구성된 쿼리는 Elasticsearch가 많은 작업을 수행하도록 강제하여 지연 시간을 증가시킬 수 있습니다.

  • 광범위한 쿼리: 충분한 필터링 없이 많은 수의 문서나 필드를 스캔하는 쿼리입니다.
    • 예시: 대규모 인덱스에 대한 match_all 쿼리.
  • 깊은 페이지 매김: fromsize를 사용하여 매우 큰 페이지를 요청하는 것입니다. 사용자 대상의 깊은 페이지 매김의 경우 안정적인 정렬 및 시점 검색과 함께 search_after를 선호하세요. 스크롤은 주로 배치 처리 또는 재색인 작업에 사용하세요.
  • 복잡한 집계: 특히 광범위한 쿼리와 결합될 때 지나치게 복잡하거나 리소스를 많이 사용하는 집계입니다.
  • 와일드카드 쿼리: 선행 와일드카드(예: *term)는 역색인 조회를 효과적으로 사용할 수 없기 때문에 특히 비효율적입니다. 후행 와일드카드는 일반적으로 더 낫지만 대규모 데이터 세트에서는 여전히 느릴 수 있습니다.
  • 정규 표현식 쿼리: 계산 비용이 많이 들 수 있으므로 드물게 사용해야 합니다.

2. 매핑 문제

데이터가 인덱싱되는 방식(매핑에 의해 정의됨)은 검색 속도에 큰 영향을 미칩니다. 잘못된 매핑 선택은 비효율적인 인덱싱과 느린 검색으로 이어질 수 있습니다.

  • 동적 매핑: 편리하지만 동적 매핑은 예기치 않은 필드 유형이나 불필요한 analyzed 필드 생성을 초래하여 인덱스 크기와 검색 오버헤드를 증가시킬 수 있습니다.
  • text vs. keyword 필드: keyword 필드가 더 적합한 경우 정확한 일치 또는 정렬/집계에 text 필드를 사용하는 것입니다. text 필드는 전문 검색을 위해 분석되는 반면, keyword 필드는 있는 그대로 인덱싱되어 정확한 일치, 정렬 및 집계에 이상적입니다.
    • 예시: 제품 ID(PROD-123)로 필터링해야 하는 경우 text가 아닌 keyword로 매핑해야 합니다.
    PUT my-index
    {
      "mappings": {
        "properties": {
          "product_id": {
            "type": "keyword"
          }
        }
      }
    }
    
  • 오래된 _all 필드 가정: 이전 Elasticsearch 버전에는 다른 필드의 콘텐츠를 인덱싱하는 _all 필드가 있었습니다. 최신 버전에서는 제거되었으므로 결합된 검색 텍스트가 필요할 때 명시적 필드나 copy_to를 사용하세요.
  • 중첩 데이터 구조: nested 데이터 유형을 사용하면 관계를 유지하는 데 강력할 수 있지만, 주의해서 쿼리하지 않으면 flattened 또는 object 유형에 비해 쿼리에 더 많은 리소스가 필요할 수 있습니다.

3. 하드웨어 및 클러스터 구성

기본 인프라와 Elasticsearch 구성 방식은 성능에 중요한 역할을 합니다.

  • 불충분한 하드웨어 리소스:
    • CPU: 높은 CPU 사용량은 비효율적인 쿼리나 과도한 인덱싱/검색 부하를 나타낼 수 있습니다.
    • RAM: RAM이 부족하면 운영 체제가 메모리를 스왑함에 따라 디스크 I/O가 증가합니다. Elasticsearch는 또한 JVM 힙과 OS 파일 시스템 캐시에 크게 의존합니다.
    • 디스크 I/O: 느린 디스크(특히 HDD)는 주요 병목 현상입니다. 프로덕션 Elasticsearch 클러스터에는 SSD를 사용하는 것이 좋습니다.
  • 샤드 크기 및 개수:
    • 너무 많은 작은 샤드: 각 샤드에는 오버헤드가 있습니다. 매우 많은 수의 작은 샤드는 클러스터를 압도할 수 있습니다.
    • 너무 적은 큰 샤드: 큰 샤드는 복구 시간이 길어지고 부하 분산이 고르지 않을 수 있습니다.
    • 일반 지침: 수십 기가바이트의 샤드는 많은 로깅 및 검색 워크로드에서 일반적이지만, 적절한 크기는 데이터 볼륨, 쿼리 패턴, 복구 목표 및 노드 리소스에 따라 다릅니다.
  • 복제본: 복제본은 가용성과 읽기 처리량을 향상시키지만 인덱싱 오버헤드와 디스크 공간 사용량도 증가시킵니다. 너무 많은 복제본은 리소스에 부담을 줄 수 있습니다.
  • JVM 힙 크기: 잘못 구성된 JVM 힙은 가비지 수집 일시 중지를 유발할 수 있습니다. 일반적인 시작점은 시스템 RAM의 절반을 넘지 않으면서 운영 체제 파일 캐시에 충분한 메모리를 남겨두는 것입니다. Elasticsearch 버전의 힙 지침을 따르세요.
  • 네트워크 지연 시간: 분산 환경에서 노드 간 네트워크 지연 시간은 노드 간 통신 및 검색 조정에 영향을 미칠 수 있습니다.

4. 검색에 영향을 미치는 인덱싱 성능 문제

이 문서는 검색에 초점을 맞추고 있지만, 인덱싱 중 문제는 간접적으로 검색 속도에 영향을 미칠 수 있습니다.

  • 높은 인덱싱 부하: 클러스터가 인덱싱 요청을 따라잡는 데 어려움을 겪으면 검색 성능에 영향을 미칠 수 있습니다. 이는 종종 불충분한 하드웨어나 최적화되지 않은 인덱싱 전략 때문입니다.
  • 많은 세그먼트 수: 정기적인 세그먼트 병합 없이 빈번한 인덱싱은 많은 수의 작은 세그먼트로 이어질 수 있습니다. Elasticsearch는 자동으로 세그먼트를 병합하지만 이 프로세스는 리소스를 많이 사용하며 일시적으로 검색 속도를 저하시킬 수 있습니다.

느린 쿼리 진단

수정 사항을 구현하기 전에 어떤 쿼리가 느리고 그 이유를 식별해야 합니다.

1. Elasticsearch 느린 로그

느린 쿼리를 기록하도록 Elasticsearch를 구성하세요. 이것이 문제가 되는 검색 요청을 식별하는 가장 직접적인 방법입니다.

  • 구성: 인덱스별로 느린 로그 임계값을 설정합니다. Elasticsearch가 예상하는 로그 수준 접미사(예: warn, info, debug, trace)를 사용하세요.
    PUT _settings
    {
      "index": {
        "search": {
          "slowlog": {
            "threshold": {
              "query": {
                "warn": "1s"
              },
              "fetch": {
                "warn": "1s"
              }
            }
          }
        }
      }
    }
    
    • query: 쿼리 단계를 실행하는 데 지정된 임계값보다 오래 걸리는 쿼리를 기록합니다.
    • fetch: 가져오기 단계(실제 문서 검색)를 실행하는 데 지정된 임계값보다 오래 걸리는 쿼리를 기록합니다.
  • 로그 위치: 느린 로그는 Elasticsearch 로깅을 통해 기록되며 패키지, 배포 플랫폼 및 로깅 구성에 따라 별도의 검색 느린 로그 파일에 나타나는 경우가 많습니다.

2. Elasticsearch 모니터링 도구

모니터링 도구를 활용하여 클러스터 상태 및 성능에 대한 통찰력을 얻으세요.

  • Elastic Stack 모니터링: 구성된 경우 CPU, 메모리, 디스크 I/O, JVM 힙 사용량, 쿼리 지연 시간, 인덱싱 속도 등에 대한 대시보드를 제공합니다.
  • APM (애플리케이션 성능 모니터링): 애플리케이션에서 Elasticsearch로의 요청을 추적하여 애플리케이션 또는 Elasticsearch 수준의 병목 현상을 식별하는 데 도움이 될 수 있습니다.
  • 타사 도구: 많은 외부 도구가 고급 모니터링 및 분석 기능을 제공합니다.

3. 분석 API

_analyze API는 텍스트 필드가 토큰화되고 처리되는 방식을 이해하는 데 도움이 되며, 이는 전문 검색 문제를 디버깅하는 데 중요합니다.

  • 예시: 쿼리 문자열이 처리되는 방식을 확인합니다.
    GET my-index/_analyze
    {
      "field": "my_text_field",
      "text": "Quick brown fox"
    }
    

4. 프로필 API

매우 특정한 쿼리 성능 튜닝의 경우 프로필 API는 검색 요청의 각 구성 요소에 대한 자세한 타이밍 정보를 제공할 수 있습니다.

  • 예시:
    GET my-index/_search
    {
      "profile": true,
      "query": {
        "match": {
          "my_field": "search term"
        }
      }
    }
    

느린 쿼리 수정: 솔루션 및 최적화

근본 원인을 식별한 후에는 목표 지향적인 솔루션을 구현할 수 있습니다.

1. 쿼리 최적화

  • 필터 컨텍스트: 점수가 필요하지 않은 조건에는 filter 절을 사용하세요. Elasticsearch는 이를 예/아니오 필터로 실행하고 자주 사용되는 필터를 캐시할 수 있습니다.
    GET my-index/_search
    {
      "query": {
        "bool": {
          "must": [
            { "match": { "title": "elasticsearch" } }
          ],
          "filter": [
            { "term": { "status": "published" } },
            { "range": { "publish_date": { "gte": "now-1M/M" } } }
          ]
        }
      }
    }
    
  • 선행 와일드카드 피하기: 가능하면 선행 와일드카드(*term)를 피하도록 쿼리를 다시 작성하세요. ngram 토크나이저나 대체 검색 방법을 고려하세요.
  • 필드 스캔 제한: 쿼리와 응답의 _source 필터링에 필요한 필드만 지정하세요.
  • 깊은 페이지 매김에 search_after 사용: 얕은 페이지를 넘는 대화형 페이지 매김의 경우 결정론적 정렬과 함께 search_after를 사용하세요. 대규모 내보내기의 경우 Elasticsearch 버전과 워크로드에 따라 스크롤 또는 시점 검색과 search_after를 사용하세요.
  • 집계 단순화: 복잡한 집계를 검토하고 최적화하세요. 집계의 깊은 페이지 매김에는 composite 집계를 사용하는 것을 고려하세요.
  • 정확한 일치/정렬을 위한 keyword: 정확한 일치, 정렬 또는 집계에 사용되는 필드가 keyword로 매핑되었는지 확인하세요.

2. 매핑 개선

  • 명시적 매핑: 동적 매핑에만 의존하지 말고 인덱스에 대한 명시적 매핑을 정의하세요. 이렇게 하면 필드가 올바른 유형으로 인덱싱됩니다.
  • _sourcedoc_values에 주의: _source를 비활성화하면 업데이트, 재색인, 강조 표시 및 디버깅 워크플로가 중단될 수 있습니다. 정렬 또는 집계에 사용되는 필드에서 doc_values를 비활성화하면 해당 워크로드에 해가 됩니다. 이를 기본 검색 수정 사항이 아닌 스토리지 최적화로 취급하세요.
  • index_options: text 필드의 경우 index_options를 미세 조정하여 필요한 정보만 저장하세요(예: 구문 쿼리의 경우 위치).

3. 하드웨어 및 클러스터 튜닝

  • 하드웨어 업그레이드: 더 빠른 CPU, 더 많은 RAM, 특히 SSD에 투자하세요.
  • 샤딩 전략 최적화: 샤드 수와 크기를 검토하세요. 필요한 경우 최적화된 샤딩 전략으로 새 인덱스에 데이터를 재색인하는 것을 고려하세요. ILM(인덱스 수명 주기 관리)과 같은 도구를 사용하여 시간 기반 인덱스와 해당 샤딩을 관리하세요.
  • JVM 힙 조정: JVM 힙 크기가 올바르게 설정되었는지(예: RAM의 50%, 최대 30-32GB) 확인하고 가비지 수집을 모니터링하세요.
  • 노드 역할: 리소스 경합을 방지하기 위해 여러 노드에 역할(마스터, 데이터, 수집, 조정)을 분산하세요.
  • 복제본 증가(읽기 중심 워크로드의 경우): 병목 현상이 읽기 처리량이고 인덱싱이 아닌 경우 복제본을 더 추가하는 것을 고려하되 인덱싱에 미치는 영향을 모니터링하세요.

4. 인덱스 최적화

  • 강제 병합: 세그먼트 수를 줄여 검색과 스토리지에 도움이 되는 읽기 전용 인덱스에서만 _forcemerge를 실행하세요. 이는 리소스를 많이 사용하며 인덱스가 계속 쓰기를 수신하는 경우 다시 쓰는 데 비용이 많이 드는 매우 큰 세그먼트를 생성할 수 있습니다.
    POST my-index/_forcemerge?max_num_segments=1
    
  • 인덱스 수명 주기 관리(ILM): ILM을 사용하여 오래되고 비활성화된 인덱스에 대한 강제 병합과 같은 최적화 단계를 포함하여 인덱스를 자동으로 관리하세요.

성능 유지를 위한 모범 사례

  • 정기적으로 모니터링: 지속적인 모니터링은 성능 저하를 조기에 발견하는 데 중요합니다.
  • 변경 사항 테스트: 프로덕션에 중요한 변경 사항을 배포하기 전에 스테이징 환경에서 테스트하세요.
  • 데이터 및 쿼리 이해: 최상의 최적화는 상황에 따라 다릅니다. 어떤 데이터가 있고 어떻게 쿼리하는지 알아야 합니다.
  • Elasticsearch 업데이트 유지: 최신 버전에는 종종 성능 개선 및 버그 수정이 포함됩니다.
  • 클러스터 크기 적절히 조정: 리소스를 과도하게 프로비저닝하거나 부족하게 프로비저닝하지 마세요. 정기적으로 클러스터의 요구 사항을 평가하세요.

핵심 요약

느린 Elasticsearch 검색을 수정하려면 먼저 측정하세요. 느린 로그는 어떤 요청이 문제인지 알려주고, 프로필 API는 시간이 어디에 소요되는지 보여주며, 클러스터 메트릭은 쿼리가 힙 압박, 디스크 I/O, 인덱싱 또는 샤드 오버헤드와 경쟁하고 있는지 보여줍니다. 한 번에 하나씩 변경하고 동일한 쿼리를 다시 실행한 후 지연 시간과 리소스 사용량이 개선된 경우에만 결과를 유지하세요.