Elasticsearch JVMヒープサイズの理解とパフォーマンスチューニング

Elasticsearch JVMヒープのサイジング、GC症状の読み解き方、検索パフォーマンスを損なうメモリ設定を避けるための実践的なガイダンス。

Elasticsearch JVMヒープサイズの理解とパフォーマンスチューニング

Elasticsearch JVMヒープサイズは、よくある設定の一つで、早すぎる調整と遅すぎる非難の対象になりがちです。遅いクラスターが常にヒープを必要とするわけではありません。時には逆で、ヒープは十分大きいが、オペレーティングシステムがファイルシステムキャッシュに残すメモリが少なすぎて、Luceneがディスクにアクセスする頻度が増えることがあります。また、ヒープが本当に小さすぎてガベージコレクションが常に実行され、すべての検索がセメントの中を歩くように感じられることもあります。

実用的な目標は魔法の数字を見つけることではありません。目標は、Elasticsearchにクラスターメタデータ、インデックスバッファ、集計、クエリ処理、キャッシュに十分なヒープを与えつつ、Luceneセグメントファイルとオペレーティングシステムのためにヒープ外に十分なRAMを残すことです。一つだけ覚えておくべきことは、Elasticsearchのパフォーマンスはヒープとオフヒープメモリの両方に依存するということです。

まず、2種類のメモリプレッシャーを区別します。JVMヒーププレッシャーは、高いheap.percent、長いガベージコレクションポーズ、親サーキットブレーカー例外、フィールドデータプレッシャー、またはOutOfMemoryErrorとして現れます。オフヒーププレッシャーは、ヒープが正常に見えても検索が遅い、高いディスク読み取り、スワップアクティビティ、再起動後のキャッシュヒット率の低下として現れます。ヒープを増やすことは最初のケースに役立ちますが、2番目のケースを悪化させる可能性があります。

ほとんどの自己管理クラスターでは、古い経験則がまだ出発点として機能します。ヒープをマシンのRAMの半分以下に設定し、圧縮通常オブジェクトポインタのしきい値未満に保ちます。人々はそのしきい値を「約32 GB」とよく引用します。実際には、多くの運用者は26〜31 GBの範囲に留めます。正確なカットオフはJVMとランタイムレイアウトに依存するためです。Elasticsearchは起動時に圧縮通常オブジェクトポインタが有効かどうかをログに記録します。起動ログをノードの真実の情報源として扱います。

最新のElasticsearchリリースでは、自動ヒープサイジングがノードの役割と利用可能なメモリに基づいて適切な値を設定する場合があります。これは特に小規模クラスターや標準的なデプロイメントで有用です。手動チューニングは、ノードが異常なワークロード(大量の集計、大きなマッピング、多数のシャード、インジェストパイプライン、変換ジョブ、機械学習の役割、またはホット検索と高インデックスボリュームの混合)を持つ場合に依然として重要です。

簡単な例を示します。インデックスと検索の両方を処理する64 GBのホットデータノードがあるとします。30 GBのヒープは一般的な出発点です。RAMの約半分をOSページキャッシュとネイティブメモリに残します。同じノードが多数の小さなシャードと高カーディナリティ集計を持つロギングクラスターの一部である場合、ヒーププレッシャーが依然として発生する可能性があります。修正は、より良いシャード設計やマッピングのクリーンアップであり、自動的に40 GBのヒープにすることではありません。圧縮ポインタのしきい値を超えると、オブジェクトポインタサイズが増加し、実効ヒープ効率が低下する可能性があります。

最小ヒープと最大ヒープを同じ値に設定します。Elasticsearchはトラフィックを処理中にヒープのサイズ変更に時間を費やすべきではありません。

-Xms30g
-Xmx30g

インストールがサポートしている場合は、パッケージ化されたjvm.optionsファイルを直接編集するのではなく、jvm.options.d/の下のファイルを使用します。パッケージインストールの場合、通常は/etc/elasticsearch/jvm.options.d/heap.optionsのようなものです。Dockerの場合は、サポートされている環境変数またはマウントされた設定を通じてヒープ設定を渡します。同じ役割のノードで設定を一貫させますが、すべての役割が同じヒープを必要とするとは想定しないでください。専用のマスター適格ノードは、インデックス、フィールド、またはシャードが多すぎるためにクラスターが非常に大きなメタデータを持っている場合を除き、ビジーデータノードよりもはるかに少ないヒープを必要とすることがよくあります。

ヒープを変更する前に、現在の動作のスナップショットを取得します。JVM統計を確認します。

GET _nodes/stats/jvm?filter_path=nodes.*.jvm.mem,nodes.*.jvm.gc

次に、ブレーカーとフィールドデータを確認します。

GET _nodes/stats/breaker,indices/fielddata?pretty

また、シャードとマッピングを確認します。数千の小さなシャードを持つクラスターは、データ量が大きくなくてもオーバーヘッドでヒープを消費する可能性があります。

GET _cat/shards?v&bytes=gb
GET _cluster/stats?filter_path=indices.count,indices.shards,indices.mappings

症状は見出しの数字よりも重要です。ガベージコレクションが迅速にヒープを解放する場合、バースト中にヒープが70〜85%程度になるのは正常です。ヒープが90%台後半まで上昇し、そのまま留まるのは別です。高いパーセンテージ自体よりも、長い古い世代のGCポーズの方が問題です。GCが実行されるたびに検索がタイムアウトする場合、平均ヒープチャートが許容範囲に見えてもユーザーは気にしません。

一般的な本番環境のミスは、ヒープを悪いマッピングの応急処置として使用することです。fielddata: trueで分析済みのtextフィールドをソートまたは集計すると、多くのヒープを消費する可能性があります。より良い修正は、通常、keywordサブフィールド、低カーディナリティフィールド、または異なる集計設計です。もう一つのミスは、動的マッピングが任意のJSONキーから数千のフィールドを作成することを許可することです。ヒープはマッピング、クラスター状態、クエリ構造に消えます。動的フィールドに境界を設定して、運用上の問題になる前に防ぎます。

集計には特別な注意が必要です。高カーディナリティフィールドに対する用語集計は、大きなメモリ内構造を作成する可能性があります。誰かがuser_idsession_id、または完全なURLで長い時間範囲にわたってグループ化するダッシュボードを実行すると、通常の検索が正常に見えてもヒーププレッシャーが急上昇する可能性があります。より小さな時間枠、作業セットを絞り込むフィルター、ページネーションのためのcomposite集計、または適切な場所での事前集計ロールアップを使用します。ヒープを増やすと障害を遅らせるかもしれませんが、無制限の集計を安価にすることはありません。

インデックス作成には独自のヒープパターンがあります。バルクリクエストは一時的なプレッシャーを生み出します。非常に大きなバルクペイロードは、Elasticsearchが一度に多くの作業を保持することを強制する可能性があります。インデックス作成の拒否やインジェスト中のヒープスパイクが見られる場合は、より小さなバルクバッチとより多くのクライアント側の並行性制御を試みます。有用な開始範囲は、多くの場合、バルクリクエストあたり数メガバイトであり、実際のドキュメントでテストして増やします。適切な値は、ドキュメントサイズ、インジェストパイプライン、レプリカ、リフレッシュ間隔、ストレージ速度に依存します。

オペレーティングシステムを無視しないでください。スワップを無効にするか、Elasticsearchメモリがスワップアウトされないようにホストを設定します。スワッピングは、JVMポーズが非常に大きくなるため、回復可能なメモリ問題を長時間の停止に変える可能性があります。bootstrap.memory_lock: trueを使用する場合は、プロセスがメモリをロックする権限を持っていることを確認し、設定が機能したと想定するのではなく、起動時に検証します。

ヒープを変更した後、本番クラスターで一度に1ノードずつ再起動し、次のノードに移る前にシャードリカバリが落ち着くのを待ちます。少なくとも1つの通常のトラフィックサイクルで、検索レイテンシ、GCポーズ、ディスク読み取り、インデックススループットを監視します。静かな時間帯に良いように見える変更が、朝のダッシュボードラッシュ時に失敗する可能性があります。

適切なチューニング後もノードがヒーププレッシャーに達し続ける場合は、一歩下がってヒープが何を保持しているかを尋ねます。シャードが多すぎる、フィールドが多すぎる、テキストのフィールドデータ、過大な集計、重いスクリプト、同じノードでの役割の混在が、「ElasticsearchはすべてのRAMを必要とする」よりも一般的な原因です。最も強力なヒープチューニング作業は、多くの場合、より小さなマッピング、より少ないシャード、より良いクエリ制限、または専用のインジェスト層で終わります。

ヒープチューニングは一度きりの儀式ではありません。キャパシティ管理の一部です。データ量が増加したり、ダッシュボードが変更されたり、新しいチームがより広いドキュメントを送信し始めると、メモリプロファイルも変化します。ヒープサイジングを退屈に保ちます。測定し、一つのことを変更し、安全に再起動し、実際のワークロードデータで検証します。