ピークパフォーマンスのための Elasticsearch メモリ使用量の最適化

ピークパフォーマンスを実現するために、Elasticsearch のメモリ管理をマスターしましょう。このガイドでは、JVM ヒープサイズの設定、インデックス作成と検索の最適化、キャッシングの活用、そして OutOfMemory エラーを防ぐためのサーキットブレーカーの導入といった重要なテクニックを深掘りします。高負荷時でも Elasticsearch クラスターが安定して応答性を維持するための実践的な戦略を学びましょう。

Elasticsearchメモリ使用量の最適化:ピークパフォーマンスを実現する

Elasticsearchのメモリ問題は、通常、検索の遅延、長時間のガベージコレクションポーズ、サーキットブレーカーエラー、またはクラスターから離脱するノードとして現れます。Elasticsearchのメモリ使用量を最適化するということは、単に -Xmx を上げるのではなく、JVMヒープ、ファイルシステムキャッシュ、シャード数、クエリ動作、インデックス作成負荷のバランスを取ることを意味します。

目標はシンプルです。Elasticsearchにクラスターとクエリ処理に十分なヒープを割り当てつつ、オペレーティングシステムがLuceneセグメントファイルをキャッシュするための十分なRAMを残すことです。

Elasticsearchのメモリコンポーネントを理解する

Elasticsearchは、大まかに2つの領域でメモリを使用します。

  • JVMヒープ: クラスターメタデータ、インデックスバッファ、クエリ構造、有効化されている場合のフィールドデータ、キャッシュ、その他のJavaオブジェクトを保持します。ヒープが少なすぎると、メモリ負荷が高まり、ブレーカーが作動します。ヒープが多すぎると、ガベージコレクションが長引き、ファイルシステムキャッシュが不足する可能性があります。
  • ファイルシステムキャッシュとネイティブメモリ: オペレーティングシステムは、JVMヒープの外部にあるLuceneインデックスファイルをキャッシュします。Elasticsearchは、ネットワーキング、スレッドスタック、メモリマップドファイルにもネイティブメモリを使用します。

JVMヒープサイズを設定する

ヒープサイジングは、最初に確認すべき設定です。Elasticsearchは、インストール方法に応じて jvm.options ファイルまたは環境固有のJVMオプションを使用します。

XmsXmx を同じ値に設定する

ノードの実行中にJVMがヒープのサイズを変更しないように、-Xms-Xmx を同じ値に設定します。

経験則として、ヒープは物理RAMの約半分以下に保ち、圧縮オブジェクトポインタのしきい値を超えないようにします。実際には、多くの本番ノードはヒープを約30 GB未満に抑えていますが、お使いのElasticsearchとJVMのバージョンに応じた正確なしきい値とガイダンスを確認する必要があります。

例:

-Xms4g
-Xmx4g

これにより、初期ヒープと最大ヒープの両方が4 GBに設定されます。

ヒープ使用量を監視する

Kibana Stack Monitoring、Prometheusエクスポーター、またはNodes Stats APIを使用します。

curl -X GET "localhost:9200/_nodes/stats/jvm?pretty"

heap_used_percent、ガベージコレクション時間、旧世代のメモリ負荷、サーキットブレーカーの作動状況を監視します。ガベージコレクション後もヒープ使用率が長期間高いままである場合は、通常、ヒープの消費を減らすか、容量を追加する必要があることを意味します。

シャードとクエリのメモリ負荷を減らす

インデックスレイアウトとクエリ形状は、メモリに直接影響を与えます。

シャードサイズと数

すべてのシャードにはオーバーヘッドがあります。小さなシャードが多すぎると、ヒープを浪費し、クラスター操作が遅くなります。非常に大きなシャードは、リカバリと再配置を困難にする可能性があります。多くのクラスターは、数十ギガバイトのシャードサイズでうまく機能しますが、ログ、時系列データ、検索負荷の高いインデックスでは、異なる目標が必要になる場合があります。

たとえば、毎日のログインデックスが20 GBのデータに対して30のプライマリシャードを作成する場合、多数の小さなシャードに対してオーバーヘッドを支払っていることになります。保持期間とクエリパターンによっては、1つまたは2つのプライマリシャードの方が管理しやすい場合があります。

セグメントマージ

Elasticsearchは、インデックス作成にLuceneセグメントを使用します。時間の経過とともに、小さなセグメントはより大きなセグメントにマージされます。このプロセスはメモリを大量に消費する可能性があります。Elasticsearchはマージを自動的に処理しますが、特にインデックス作成負荷が高い場合、その影響を理解することは有益です。

検索と集約の最適化

  • 集約にはキーワードフィールドを使用する: keyword、数値、日付、またはその他のdoc-values対応フィールドで集約およびソートします。ヒープコストを理解していない限り、大きな text フィールドで fielddata を有効にしないでください。
  • 高コストなクエリを制限する: 先頭ワイルドカードや広範な正規表現クエリはコストが高くなる可能性があります。部分一致が必要なユースケースでは、構造化フィールド、プレフィックス、n-gram、またはsearch-as-you-typeマッピングを優先します。
  • 遅い検索をプロファイリングする: ステージング環境でプロファイルAPIを使用して、最も多くの処理を生成するクエリ句を見つけます。

キャッシュを意図的に使用する

Elasticsearchには複数のキャッシュがあります。これらは繰り返しの処理を高速化しますが、メモリも消費します。

  • シャードリクエストキャッシュ: 対象となるリクエストのシャードレベルの検索結果をキャッシュします。多くの場合、ほとんど変更されていないデータに対する繰り返しの集約スタイルのクエリに役立ちます。そのサイズは以下で制御されます。

    indices.requests.cache.size: 5%
    

    この例では、シャードリクエストキャッシュのサイズをヒープの5%に設定しています。

  • ノードクエリキャッシュ: フィルターコンテキストの結果をキャッシュします。そのサイズは個別に制御されます。

    indices.queries.cache.size: 10%
    
  • フィールドデータキャッシュ: ヒープを消費し、テキストフィールドでfielddataを有効にすると急速に増加する可能性があります。より大きなフィールドデータキャッシュに依存するのではなく、フィールドを正しくマッピングすることを優先します。

OutOfMemoryエラーを防ぐ

OutOfMemoryエラーは、通常、持続的なメモリ負荷の最終結果です。修正方法は「すべての制限を引き上げる」ことではありません。

ガベージコレクションを症状として扱う

最近のElasticsearchバージョンでは、サポートされているJVMのデフォルトが選択されます。バージョン固有のガイダンスと測定値がない限り、カスタムのガベージコレクタチューニングは避けてください。長時間のポーズは、通常、過剰なシャーディング、高コストな集約、フィールドデータ、過剰なヒープ負荷、またはノード不足を示しています。

GC問題の主な指標は次のとおりです。

  • GC時間が長い。
  • ストップザワールドポーズが長い。
  • 各コレクション後にヒープ使用量が制限近くまで戻る。
  • 大規模な検索、バルクインデックス作成、または集約中のOOMエラー。

サーキットブレーカーを尊重する

サーキットブレーカーはメモリ使用量を見積もり、ノードのメモリを使い果たす前に操作を拒否します。

  • フィールドデータブレーカー: フィールドデータに使用されるヒープを制限します。
  • リクエストブレーカー: リクエストデータ構造を完了するために使用されるメモリを制限します。
  • ペアレントブレーカー: 組み合わせたブレーカーの見積もりを追跡します。

ブレーカーの統計は以下で表示します。

curl -X GET "localhost:9200/_nodes/stats/breaker?pretty"

一部のブレーカー設定はクラスター設定を通じて変更できますが、ブレーカーが作動する理由を理解した後にのみ行ってください。作動したブレーカーは、多くの場合、ノードをOOMから保護しています。

監視とアラート

以下にアラートを設定します。

  • ガベージコレクション後のJVMヒープ使用量。
  • ガベージコレクション時間と長時間のポーズ。
  • サーキットブレーカーの作動。
  • インデックス作成負荷と拒否されたスレッドプールタスク。
  • OSのメモリ負荷とスワップ使用量。
  • ノードあたりのシャード数と異常に大きな集約。

まとめ

ヒープサイジングから始め、次にシャード数、フィールドマッピング、大規模な集約、繰り返し発生するサーキットブレーカーの作動を確認します。クリーンアップ後もノードに負荷がかかっている場合は、警告サインを大きな制限で隠すのではなく、容量を追加するか、ワークロードを分割します。