Elasticsearch 벤치마킹: 성능 검증을 위한 도구와 기법

실제 워크로드, Rally 트랙, 반복 가능한 테스트, 적절한 인덱싱 및 검색 메트릭을 사용하여 Elasticsearch를 벤치마킹합니다.

Elasticsearch 벤치마킹: 성능 검증을 위한 도구와 기법

Elasticsearch 벤치마킹은 실용적인 질문에 답합니다: 클러스터가 사용자가 실제로 생성하는 인덱싱 및 검색 부하를 처리할 수 있을까요? 반복 가능한 테스트 없이는 웜 캐시, 조용한 네트워크 또는 운 좋은 쿼리 실행을 실제 성능 개선으로 착각할 수 있습니다.

유용한 벤치마크는 매핑, 샤드 수, 하드웨어, JVM 설정 또는 쿼리 코드를 변경한 후 다시 실행할 수 있는 벤치마크입니다.

벤치마킹이 필수적인 이유

벤치마킹은 단순히 몇 개의 쿼리를 실행하는 것 이상입니다. 다양한 워크로드에서 Elasticsearch 클러스터의 성능을 측정하는 체계적인 프로세스입니다. 다음은 벤치마킹이 필수적인 이유입니다:

  • 객관적 측정: 성능을 평가할 수 있는 정량적 데이터를 제공합니다. 추측하는 대신 변경 사항이 얼마나 더 빠르거나 느린지 정확히 알 수 있습니다.
  • 병목 현상 식별: 느린 쿼리, 과부하된 노드, 비효율적인 인덱싱 등 시스템 성능을 저해하는 특정 영역을 정확히 찾아내는 데 도움이 됩니다.
  • 최적화 검증: 성능 튜닝 중 변경된 사항(예: 인덱스 설정, 샤드 할당, 하드웨어 업그레이드)이 원하는 효과를 내는지 확인하는 데 중요합니다.
  • 용량 계획: 현재 한계와 증가하는 부하에서의 동작 방식을 이해하여 클러스터 확장에 대한 결정을 내리는 데 도움이 됩니다.
  • 회귀 테스트: 새로운 코드 배포 또는 구성 변경이 성능에 부정적인 영향을 미치지 않도록 보장합니다.

모니터링해야 할 주요 메트릭

벤치마킹 시 사용자 경험과 시스템 상태를 직접적으로 반영하는 메트릭에 집중하세요. 일반적으로 다음과 같이 분류할 수 있습니다:

인덱싱 메트릭

  • 인덱싱 처리량: 초당 인덱싱되는 문서 수입니다. 일반적으로 높을수록 좋습니다.
  • 인덱싱 지연 시간: 문서가 인덱싱된 후 검색 가능해질 때까지 걸리는 시간입니다. 낮을수록 좋습니다.
  • 새로고침 간격 영향: refresh_interval 설정 변경이 인덱싱 속도와 검색 가시성에 미치는 영향입니다.

검색 메트릭

  • 검색 처리량: 초당 처리되는 검색 요청 수입니다.
  • 검색 지연 시간: 검색 쿼리에 응답하는 데 걸리는 시간입니다. 일반적으로 다음과 같이 세분화됩니다:
    • 총 지연 시간: 종단 간 시간입니다.
    • 쿼리 지연 시간: 검색 쿼리 자체를 실행하는 데 소요된 시간입니다.
    • 페치 지연 시간: 실제 문서를 검색하는 데 소요된 시간입니다.
  • 오류율 및 시간 초과: 실패한 요청은 빠른 성공 요청만큼 중요합니다.

클러스터 상태 메트릭

  • CPU 사용률: 높은 CPU는 비효율적인 쿼리 또는 인덱싱을 나타낼 수 있습니다.
  • 메모리 사용률: JVM 힙 및 OS 파일 시스템 캐시에 중요합니다.
  • 디스크 I/O: 여기서 병목 현상이 발생하면 인덱싱과 검색 모두에 심각한 영향을 미칠 수 있습니다.
  • 네트워크 트래픽: 분산 환경에서 중요합니다.
  • JVM 힙 사용률: 일시 중지를 유발할 수 있는 가비지 수집 활동을 모니터링합니다.

인기 있는 Elasticsearch 벤치마킹 도구

여러 도구가 부하를 시뮬레이션하고 Elasticsearch 성능을 측정하는 데 도움이 될 수 있습니다. 올바른 도구를 선택하는 것은 특정 요구 사항과 기술 전문 지식에 따라 달라집니다.

1. Rally

Rally는 Elasticsearch의 공식 벤치마킹 도구입니다. 강력하고 유연하며 실제 사용자 워크로드를 시뮬레이션하도록 설계되었습니다.

주요 기능:

  • 워크로드 정의: Rally DSL을 사용하여 복잡한 인덱싱 및 검색 작업을 정의할 수 있습니다.
  • 데이터 생성: 합성 데이터를 생성하거나 기존 데이터 세트를 사용할 수 있습니다.
  • 메트릭 수집: 테스트 실행 중에 자세한 성능 메트릭을 수집합니다.
  • 통합: Elasticsearch 및 OpenSearch와 완벽하게 작동합니다.

예: 기본 Rally 벤치마크 실행

Rally는 일반적으로 명명된 트랙과 챌린지를 실행합니다. 기존 로컬 클러스터에 대해 표준 벤치마크를 실행하려면 기본 제공 트랙으로 시작하세요:

esrally race --pipeline=benchmark-only --target-hosts=localhost:9200 --track=geonames

트랙을 선택하기 전에 사용 가능한 트랙을 나열하세요:

esrally list tracks

애플리케이션별 워크로드의 경우 매핑, 문서 및 일반적인 쿼리를 미러링하는 사용자 정의 Rally 트랙을 만드세요. Rally 버전의 트랙 형식에 대해 확인하지 않는 한 임시 JSON 스니펫은 사용하지 마세요.

2. 수집 부하를 위한 Logstash 또는 Beats

주로 수집 도구이지만 Logstash는 Elasticsearch를 공급하는 파이프라인을 테스트하려는 경우 기본 인덱싱 부하에 사용할 수 있습니다.

주요 기능:

  • 입력 플러그인: 다양한 소스의 데이터 수집을 시뮬레이션할 수 있습니다.
  • 출력 플러그인: elasticsearch 출력 플러그인은 Elasticsearch로 데이터를 보내는 데 사용됩니다.
  • 필터링: 인덱싱 전에 데이터 변환을 허용합니다.

예: 인덱싱 부하 시뮬레이션

Logstash 파이프라인을 구성하여 임의의 데이터를 생성하고 Elasticsearch로 보낼 수 있습니다:

logstash_indexer.conf:

input {
  generator {
    count => 1000000
    type => "event"
  }
}

filter {
  mutate {
    add_field => {
      "timestamp" => "%{+YYYY-MM-dd'T'HH:mm:ss.SSSZ}"
      "message" => "This is a test log message %{random}"
    }
    remove_field => ["random", "host"]
  }
}

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "logstash-benchmark-%{+YYYY.MM.dd}"
    # 성능 향상을 위해 벌크 API 사용 고려
    # 필요한 경우 upsert를 위한 document_id 설정 고려
  }
}

이 구성으로 Logstash를 실행하세요:

bin/logstash -f logstash_indexer.conf

성능을 평가하려면 Elasticsearch 및 Logstash 로그와 클러스터 메트릭을 모니터링하세요.

3. 사용자 정의 스크립트 (Python, Java 등)

매우 특정하거나 복잡한 시나리오의 경우 Elasticsearch 클라이언트를 사용하여 사용자 정의 스크립트를 작성하는 것이 실행 가능한 옵션입니다.

주요 기능:

  • 최대 유연성: 애플리케이션의 쿼리 패턴 및 인덱싱 요구 사항에 맞게 부하 생성을 정밀하게 조정할 수 있습니다.
  • 클라이언트 라이브러리: Elasticsearch는 여러 인기 언어(Python, Java, Go, .NET 등)에 대한 공식 클라이언트 라이브러리를 제공합니다.

예: 검색 부하를 위한 Python 스크립트

from elasticsearch import Elasticsearch
import time
import threading

# Elasticsearch 연결 구성
ES_HOST = "localhost:9200"
es = Elasticsearch([ES_HOST])

# 검색 쿼리 정의
SEARCH_QUERY = {
    "query": {
        "match": {
            "content": "example data"
        }
    }
}

NUM_THREADS = 10
QUERIES_PER_THREAD = 100

results = []

def perform_search():
    for _ in range(QUERIES_PER_THREAD):
        start_time = time.time()
        try:
            response = es.search(index="my-index-*", body=SEARCH_QUERY, size=10)
            end_time = time.time()
            results.append({
                "latency": (end_time - start_time) * 1000, # 밀리초 단위
                "success": True,
                "hits": response['hits']['total']['value']
            })
        except Exception as e:
            end_time = time.time()
            results.append({
                "latency": (end_time - start_time) * 1000,
                "success": False,
                "error": str(e)
            })
        time.sleep(0.1) # 쿼리 사이의 짧은 지연

threads = []
for i in range(NUM_THREADS):
    thread = threading.Thread(target=perform_search)
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

# 결과 분석
successful_searches = [r for r in results if r['success']]
failed_searches = [r for r in results if not r['success']]

if successful_searches:
    avg_latency = sum(r['latency'] for r in successful_searches) / len(successful_searches)
    total_hits = sum(r['hits'] for r in successful_searches)
    print(f"평균 지연 시간: {avg_latency:.2f} ms")
    print(f"총 히트 수: {total_hits}")
    print(f"성공한 검색: {len(successful_searches)}")
else:
    print("성공한 검색이 없습니다.")

if failed_searches:
    print(f"실패한 검색: {len(failed_searches)}")
    for r in failed_searches:
        print(f"  - 오류: {r['error']} (지연 시간: {r['latency']:.2f} ms)")

이 스크립트는 Python의 elasticsearch-py 클라이언트를 사용하여 동시 검색 요청을 시뮬레이션하고 지연 시간을 측정합니다.

반복 가능한 부하 테스트 설계

의미 있는 결과를 얻으려면 부하 테스트가 반복 가능해야 하며 실제 사용 패턴을 대표해야 합니다.

1. 현실적인 워크로드 정의

  • 인덱싱: 데이터 수집 속도는 얼마입니까? 문서의 크기와 복잡성은 어떻습니까? 벌크 인덱싱을 수행하고 있습니까, 아니면 단일 문서 인덱싱을 수행하고 있습니까?
  • 검색: 일반적인 쿼리 유형(예: match, term, range, 집계)은 무엇입니까? 이러한 쿼리의 복잡성은 어떻습니까? 예상되는 동시성은 얼마입니까?
  • 데이터 분포: 데이터가 인덱스와 샤드에 어떻게 분포되어 있습니까? 가능하면 프로덕션과 유사한 데이터 분포를 사용하세요.

2. 기준선 설정

변경을 수행하기 전에 선택한 벤치마크 도구를 실행하여 기준선 성능을 설정하세요. 이 기준선은 최적화의 영향을 측정하기 위한 참조 지점입니다.

3. 변수 격리

한 번에 하나의 변경만 수행하세요. 여러 최적화를 테스트하는 경우 각 개별 변경 후에 벤치마크를 실행하세요. 이는 어떤 특정 변경이 성능 향상(또는 저하)으로 이어졌는지 이해하는 데 도움이 됩니다.

4. 일관된 환경

벤치마크 실행 간에 테스트 환경이 가능한 한 일관되도록 보장하세요. 여기에는 다음이 포함됩니다:

  • 하드웨어: 동일한 사양의 동일한 노드를 사용하세요.
  • 소프트웨어: 동일한 Elasticsearch 버전, JVM 설정 및 OS 구성을 사용하세요.
  • 네트워크: 일관된 네트워크 조건을 유지하세요.
  • 데이터: 동일한 데이터 세트 또는 데이터 생성 방법을 사용하세요.

5. 충분한 테스트 기간 및 워밍업

  • 워밍업 기간: 측정을 시작하기 전에 클러스터가 워밍업되도록 허용하세요. 여기에는 캐시를 채우고 JVM을 안정화하기 위해 초기 부하를 실행하는 것이 포함됩니다.
  • 테스트 기간: 의미 있는 평균을 포착하고 일시적인 시스템 동작을 설명할 수 있을 만큼 충분히 오래 테스트를 실행하세요. 짧은 테스트는 오해의 소지가 있습니다.

6. 시스템 리소스 모니터링

Elasticsearch 노드와 벤치마크 도구를 실행하는 모든 클라이언트 노드에서 시스템 리소스(CPU, RAM, 디스크 I/O, 네트워크)를 항상 모니터링하세요. 이는 성능 메트릭을 리소스 사용률과 상호 연관시키고 병목 현상을 식별하는 데 도움이 됩니다.

벤치마킹 모범 사례

  • 자동화: 회귀를 조기에 발견하기 위해 벤치마킹을 CI/CD 파이프라인에 통합하세요.
  • 간단하게 시작: 복잡한 시나리오로 이동하기 전에 기본 인덱싱 및 검색 벤치마크부터 시작하세요.
  • 데이터 이해: 데이터의 특성(문서 크기, 필드 유형)은 성능에 큰 영향을 미칩니다.
  • 인덱싱 전략 고려: 다양한 refresh_interval, translog 설정 및 샤드 크기를 테스트하세요.
  • 쿼리 최적화: 검색 쿼리가 효율적인지 확인하세요. profile API를 사용하여 느린 쿼리를 분석하세요.
  • JVM 모니터링: 가비지 수집 로그와 힙 사용량에 특히 주의하세요.

실제로 실행할 항목 벤치마킹

프로덕션 워크로드에서 사용하는 것과 동일한 종류의 데이터, 매핑, 쿼리 및 동시성으로 Elasticsearch를 벤치마킹하세요. 기준선으로 시작하고, 하나의 변수를 변경하고, 워밍업과 안정 상태를 포함할 수 있을 만큼 충분히 오래 실행하고, 벤치마크 보고서와 함께 노드 메트릭을 유지하세요. 이를 통해 튜닝, 용량 계획 및 회귀 검사에 사용할 수 있는 증거를 얻을 수 있습니다.