Elasticsearchのベンチマーク:パフォーマンス検証のためのツールとテクニック

現実的なワークロード、Rallyトラック、再現可能なテスト、適切なインデックス作成と検索のメトリクスを用いてElasticsearchをベンチマークします。

Elasticsearchのベンチマーク:パフォーマンス検証のためのツールとテクニック

Elasticsearchのベンチマークは、実際のユーザーが生成するインデックス作成と検索の負荷をクラスターが処理できるかどうかという実用的な問いに答えます。再現可能なテストがなければ、ウォームキャッシュ、静かなネットワーク、または1回の幸運なクエリ実行を実際のパフォーマンス改善と誤認する可能性があります。

有用なベンチマークとは、マッピング、シャード数、ハードウェア、JVM設定、またはクエリコードを変更した後に再度実行できるものです。

ベンチマークが重要な理由

ベンチマークは、単にいくつかのクエリを実行するだけではありません。さまざまなワークロード下でElasticsearchクラスターのパフォーマンスを測定する体系的なプロセスです。その重要性は以下の通りです:

  • 客観的な測定:パフォーマンスを評価するための定量化可能なデータを提供します。推測する代わりに、変更によってどれだけ速くなったり遅くなったりしたかを正確に把握できます。
  • ボトルネックの特定:遅いクエリ、過負荷のノード、非効率的なインデックス作成など、システムのパフォーマンスを妨げている特定の領域を特定するのに役立ちます。
  • 最適化の検証:パフォーマンスチューニング中に行った変更(例:インデックス設定、シャード割り当て、ハードウェアアップグレード)が期待通りの効果をもたらすことを確認するために重要です。
  • キャパシティプランニング:クラスターの現在の限界と増加する負荷下での動作を理解することで、クラスターのスケーリングに関する意思決定に役立ちます。
  • リグレッションテスト:新しいコードのデプロイや設定変更がパフォーマンスに悪影響を及ぼさないことを保証します。

監視すべき主要メトリクス

ベンチマークを行う際は、ユーザーエクスペリエンスとシステムの健全性を直接反映するメトリクスに焦点を当てます。これらは一般的に以下のように分類できます:

インデックス作成メトリクス

  • インデックススループット:1秒あたりにインデックスされるドキュメント数。高いほど良いです。
  • インデックスレイテンシ:ドキュメントがインデックスされてから検索可能になるまでの時間。低いほど良いです。
  • リフレッシュ間隔の影響refresh_interval設定の変更がインデックス速度と検索の可視性にどのように影響するか。

検索メトリクス

  • 検索スループット:1秒あたりに処理される検索リクエスト数。
  • 検索レイテンシ:検索クエリに応答するのにかかる時間。これはしばしば次のように分類されます:
    • 合計レイテンシ:エンドツーエンドの時間。
    • クエリレイテンシ:検索クエリ自体の実行にかかる時間。
    • フェッチレイテンシ:実際のドキュメントを取得するのにかかる時間。
  • エラー率とタイムアウト:失敗したリクエストは、成功した高速なリクエストと同じくらい重要です。

クラスターの健全性メトリクス

  • 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の使用を検討
    # 必要に応じてupserts用の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. 現実的なワークロードの定義

  • インデックス作成:データインジェストのレートは?ドキュメントのサイズと複雑さは?バルクインデックス作成か単一ドキュメントインデックス作成か?
  • 検索:典型的なクエリタイプ(例:matchtermrange、集計)は?これらのクエリの複雑さは?予想される同時実行数は?
  • データ分布:データはインデックスとシャード全体にどのように分布しているか?可能であれば、本番環境に近いデータ分布を使用します。

2. ベースラインの確立

変更を加える前に、選択したベンチマークツールを実行してベースラインパフォーマンスを確立します。このベースラインは、最適化の影響を測定するための基準点です。

3. 変数の分離

一度に1つの変更のみを行います。複数の最適化をテストする場合は、個々の変更ごとにベンチマークを実行します。これにより、どの特定の変更がパフォーマンスの向上(または低下)につながったかを理解できます。

4. 一貫した環境

ベンチマーク実行全体でテスト環境が可能な限り一貫していることを確認します。これには以下が含まれます:

  • ハードウェア:同一仕様の同じノードを使用します。
  • ソフトウェア:同じElasticsearchバージョン、JVM設定、OS構成を使用します。
  • ネットワーク:一貫したネットワーク状態を維持します。
  • データ:同じデータセットまたはデータ生成方法を使用します。

5. 十分なテスト時間とウォームアップ

  • ウォームアップ期間:測定を開始する前に、クラスターをウォームアップします。これには、キャッシュを埋め、JVMを安定させるために初期負荷を実行することが含まれます。
  • テスト時間:意味のある平均を捉え、一時的なシステム動作を考慮するのに十分な長さのテストを実行します。短いテストは誤解を招く可能性があります。

6. システムリソースの監視

Elasticsearchノードとベンチマークツールを実行するクライアントノードの両方で、システムリソース(CPU、RAM、ディスクI/O、ネットワーク)を常に監視します。これにより、パフォーマンスメトリクスをリソース使用率と関連付け、ボトルネックを特定できます。

ベンチマークのベストプラクティス

  • 自動化:ベンチマークをCI/CDパイプラインに統合して、早期にリグレッションを発見します。
  • シンプルに始める:複雑なシナリオに進む前に、基本的なインデックス作成と検索のベンチマークから始めます。
  • データを理解する:データの性質(ドキュメントサイズ、フィールドタイプ)はパフォーマンスに大きく影響します。
  • インデックス戦略を検討する:異なるrefresh_intervaltranslog設定、シャードサイズをテストします。
  • クエリを最適化する:検索クエリが効率的であることを確認します。profileAPIを使用して遅いクエリを分析します。
  • JVMを監視する:ガベージコレクションのログとヒープ使用量に特に注意を払います。

実際に実行するものをベンチマークする

本番ワークロードで使用するのと同じ種類のデータ、マッピング、クエリ、同時実行数でElasticsearchをベンチマークします。ベースラインから始め、1つの変数を変更し、ウォームアップと定常状態を含むのに十分な長さ実行し、ベンチマークレポートとともにノードメトリクスを保持します。これにより、チューニング、キャパシティプランニング、リグレッションチェックに使用できる証拠が得られます。