Elasticsearchインデックスパフォーマンスガイド:ベストプラクティスを公開

バルクリクエスト、リフレッシュとレプリカの調整、マッピングの選択、ハードウェアの確認、シャード計画により、Elasticsearchのインデックス作成を改善します。

Elasticsearchインデックスパフォーマンスガイド:ベストプラクティスを公開

Elasticsearchのインデックスパフォーマンスは、インジェストパイプラインがバックアップし始めたり、バルクリクエストが拒否されたり、大量書き込み中に検索が遅くなったりすると顕著になります。修正は単一の魔法の設定ではほとんどなく、リクエストサイズ、リフレッシュ動作、マッピング、シャードレイアウト、ハードウェアを一緒に調整する必要があります。

このガイドでは、大規模なインジェストジョブの前および最中に適用できる実用的なElasticsearchインデックスパフォーマンスチェックに焦点を当てています。ドキュメントサイズ、アナライザー、ストレージ、レプリカ数によって結果が変わる可能性があるため、独自のクラスターからのメトリクスとともに使用してください。

インデックスプロセスの理解

最適化に入る前に、Elasticsearchがインデックスをどのように処理するかを理解することが不可欠です。ドキュメントがインデックスされると、Elasticsearchはいくつかの操作を実行します:ドキュメントの解析、フィールドの分析(トークン化、ステミングなど)、そして転置インデックスやその他のデータ構造の保存。これらの操作、特に分析とディスクI/Oは、CPUとI/Oを集中的に使用します。分散環境では、これらの操作は個々のノードによって処理されるため、クラスター全体の設定とノードリソースが重要になります。

インデックス速度に影響を与える主な要因

いくつかの要因が、Elasticsearchがドキュメントをインデックスできる速度に大きく影響を与える可能性があります:

  • ハードウェアリソース:CPU、RAM、特にディスクI/O速度が最も重要です。優れた読み取り/書き込みパフォーマンスのために、HDDよりもSSDが強く推奨されます。
  • クラスター設定:シャード割り当て、レプリケーション設定、ノードの役割が影響します。
  • インデックス戦略:データの送信方法(例:単一ドキュメントリクエスト vs バルクAPI)。
  • マッピングとデータ型:フィールドの定義方法と対応するデータ型。
  • リフレッシュ間隔:データが検索可能になる頻度。
  • トランザクションログ設定:確認応答された書き込みの耐久性設定。

インデックスパフォーマンスの最適化:ベストプラクティス

このセクションでは、Elasticsearchのインデックススループットを向上させるための実用的な戦略をカバーします。

1. バルクAPIを活用する

インデックス作成の最も基本的な最適化は、バルクAPIを使用することです。個々のインデックスリクエストを送信する代わりに(リクエストごとにネットワークオーバーヘッドと処理コストが発生します)、バルクAPIを使用すると、単一のHTTPリクエストで操作のリスト(インデックス、作成、更新、削除)を送信できます。これにより、ネットワークレイテンシが大幅に削減され、全体的なスループットが向上します。

バルクAPIのベストプラクティス:

  • バッチサイズ:バッチサイズを実験します。小さなペイロードから始め、インデックスレイテンシ、メモリプレッシャー、429拒否を監視しながら増やします。ドキュメント数だけでは不十分です。1つのドキュメントが非常に小さく、別のドキュメントが数メガバイトになる可能性があるためです。
  • 並行性:複数のスレッドまたは非同期クライアントを使用して、バルクリクエストを同時に送信します。ただし、クラスターを圧倒しないようにしてください。CPUとI/O使用率を監視して、最適なポイントを見つけます。
  • エラーハンドリング:堅牢なエラーハンドリングを実装します。バルクAPIは応答の配列を返し、各操作のステータスを確認する必要があります。

バルクリクエストの例:

{ "index": { "_index": "my-index", "_id": "1" } }
{ "field1": "value1", "field2": "value2" }
{ "index": { "_index": "my-index", "_id": "2" } }
{ "field1": "value3", "field2": "value4" }

2. インデックス設定を調整する

Elasticsearchは、インデックスプロセスを最適化するために調整できるいくつかの設定を提供します。これらは通常、インデックスごとに設定されます。

リフレッシュ間隔(index.refresh_interval

リフレッシュ間隔は、データが検索可能になる頻度を制御します。通常、アクティブなインデックスは検索されているときに約1秒ごとにリフレッシュされますが、デフォルトはバージョンとインデックスタイプによって異なる場合があります。大量のインデックス作成中は、この間隔を長くしてリフレッシュ作業を減らすことができます。-1に設定すると自動リフレッシュが無効になり、手動でリフレッシュするか自動リフレッシュを復元するまでデータは検索可能になりません。

  • 推奨事項:バルクインデックス操作の場合、検索の鮮度が必要ない場合は、一時的にindex.refresh_intervalを増やすか、-1に設定します。バルク操作が完了したら、通常の検索動作に使用する設定に戻し、必要に応じて手動リフレッシュを実行します。

インデックス設定APIを使用した例:

# リフレッシュを一時的に無効にする
PUT /my-index/_settings
{
  "index" : {
    "refresh_interval" : "-1"
  }
}

# ... バルクインデックスを実行 ...

# リフレッシュを再度有効にする
PUT /my-index/_settings
{
  "index" : {
    "refresh_interval" : "1s"
  }
}

トランザクションログの耐久性(index.translog.durability

トランザクションログは、データの耐久性を保証する書き込み前ログです。request(デフォルト)またはasyncに設定できます。asyncに設定すると、トランザクションログが非同期でフラッシュされ、インデックス速度が向上する可能性がありますが、トランザクションログがディスクに書き込まれる前にノードが障害を起こした場合、データ損失のわずかなリスクがあります。

  • 推奨事項:耐久性よりも速度が重要でないバルクインポートシナリオでは、asyncが有益な場合があります。アプリケーションのデータ損失に対する許容度を常に考慮してください。

レプリカ数(index.number_of_replicas

レプリカはプライマリシャードのコピーであり、高可用性と読み取りスケーリングに使用されます。ただし、各レプリカはすべてのインデックス操作を処理する必要があります。初期の大規模データロード中は、index.number_of_replicas0に設定すると、インデックス作成が大幅に高速化されます。データがロードされた後、レプリカ数を増やすことができます。

バルクロード中の例:

# レプリカを一時的に0に設定
PUT /my-index/_settings
{
  "index" : {
    "number_of_replicas" : "0"
  }
}

# ... バルクインデックスを実行 ...

# レプリカを復元(例:1に)
PUT /my-index/_settings
{
  "index" : {
    "number_of_replicas" : "1"
  }
}

3. マッピングを最適化する

マッピングは、ドキュメントとそのフィールドがどのように保存され、インデックスされるかを定義します。不適切に設計されたマッピングは、パフォーマンスの問題を引き起こす可能性があります。

  • 大規模データセットでの動的マッピングを避ける:便利ですが、動的マッピングはマッピングの爆発や予期しないフィールドタイプを引き起こす可能性があります。特に高ボリュームデータの場合は、インデックスに明示的なマッピングを定義します。
  • 適切なデータ型を選択する:最も効率的なデータ型を使用します。たとえば、全文検索が必要ない場合、keywordtextよりも正確な値のマッチングに効率的です。
  • 不要な機能を無効にする:特定のフィールドにnormsなどの機能が必要ない場合(例:正確なマッチや集計)、それらを無効にすることでスペースを節約し、インデックス速度を向上させることができます(norms: false)。同様に、フィールドのソートや集計に必要ない場合は、doc_valuesを無効にします。ただし、doc_valuesは一般的に集計とソートに有益であるため、これは微妙な判断です。
  • _sourceフィールド:元のJSONドキュメントが必要ない場合、_sourceを無効にするとディスクスペースと一部のI/Oを節約できますが、再インデックスができなくなり、デバッグが難しくなります。有効にしたままにする場合は、_source圧縮を検討してください。

マッピングの例(明示的な型と無効化されたnorms):

PUT /my-index
{
  "mappings": {
    "properties": {
      "timestamp": {"type": "date"},
      "message": {"type": "text", "norms": false},
      "user_id": {"type": "keyword"}
    }
  }
}

4. ハードウェアとインフラストラクチャの考慮事項

完璧なソフトウェア設定でも、不十分なハードウェアはインデックス速度を制限します。

  • ディスクI/O:高速なSSDを使用します。NVMe SSDは最高のパフォーマンスを提供します。可能であれば、インデックスノードにネットワーク接続ストレージ(NAS)を使用しないでください。
  • CPUとRAM:分析には十分なCPUコアが必要であり、十分なRAMはキャッシングと全体的なJVMパフォーマンスに役立ちます。
  • インジェストとコーディネートの容量:非常に高い取り込み率の場合、パイプライン用の専用インジェストノードや、クライアントのバルクトラフィック用のコーディネートノードを検討してください。データノードは実際のインデックス作業を行うため、CPU、メモリ、ディスクI/Oを不足させないでください。
  • ネットワーク:クライアントとElasticsearchノード間、およびクラスター内のノード間で十分な帯域幅と低レイテンシを確保します。

5. シャードのサイズと数

直接的なインデックス設定ではありませんが、シャードの数とサイズはパフォーマンスに影響します。小さなシャードが多すぎるとオーバーヘッドが増加する可能性があります。逆に、単一の巨大なシャードは管理が難しく、うまくスケールしない可能性があります。最適なパフォーマンスのために、シャードサイズを10GBから50GBの間にすることを目指しますが、これは異なる場合があります。

  • 推奨事項:大量のデータをインデックスする前に、プライマリシャード数を計画します。既存のインデックスでプライマリシャードの数を変更することは、再インデックスなしでは一般的に推奨されません。

6. インデックスライフサイクル管理(ILM)

時系列データの場合、インデックスライフサイクル管理(ILM)を使用することが重要です。ILMは主に時間の経過とともにインデックスを管理するのに役立ちますが(ロールオーバー、シュリンク、削除)、ロールオーバーアクションはサイズや経過時間に基づいて新しいインデックスを作成するように設定できます。これにより、インデックスが最適なサイズ範囲内に保たれ、間接的にインデックスパフォーマンスに利益をもたらします。

  • ロールオーバー:インデックスが特定のサイズや経過時間に達すると、ILMは自動的に新しい空のインデックスを作成し、データストリームエイリアスをそれに切り替えることができます。これにより、新しいインデックスの設定を最適化し(例:初期バルクロード中のレプリカの低減)、アクティブなインデックスを管理しやすく保つことができます。

実用的なポイント

バルクインデックス、明示的なマッピング、十分なディスクI/Oから始めてください。1回限りのロードの場合、検索の鮮度や冗長性の低下を許容できる場合にのみリフレッシュとレプリカを緩和し、その後通常の設定に戻してクラスターの健全性を確認します。実際のドキュメントでテストを続けてください。一般的なバッチサイズとシャード数は出発点にすぎません。