Elasticsearch は、ログ分析、テキスト検索、リアルタイム分析などに簡単に使い始められる NoSQL 検索および分析エンジンです。とはいえ、Elasticsearch は内部的には複雑な分散システムであり、最適なパフォーマンスを実現するためには多くの手段が必要です。
このブログでは、インデックス作成の遅さ、検索速度、シャードとインデックスのサイズ設定、マルチテナントなど、大規模な Elasticsearch のパフォーマンスに関する一般的な課題に対するソリューションについて説明します。多くのソリューションは、大規模なシステムの運用を実際に経験したエンジニアリング リーダーやアーキテクトとのインタビューやディスカッションから生まれました。
書き込みスループットが高いワークロードを扱う場合、インデックス作成のパフォーマンスを向上させるために Elasticsearch を調整する必要がある場合があります。操作がアプリケーションの検索パフォーマンスに影響を与えないように、インデックス作成に十分なリソースを用意するためのベスト プラクティスをいくつか紹介します。
更新間隔を増やす: Elasticsearch はインデックスを更新することで、新しいデータを検索できるようにします。インデックスが過去 30 秒間にクエリを受信すると、更新は 1 秒ごとに自動的に実行されるように設定されています。更新間隔を増やすと、インデックス作成用にさらに多くのリソースを確保できます。
バルク APIを使用する: 大規模なデータを取り込む場合、Update API を使用したインデックス作成には数週間かかることが知られています。このようなシナリオでは、バルク API を使用して、よりリソース効率の高い方法でデータのインデックス作成を高速化できます。バルク API を使用する場合でも、インデックスされるドキュメントの数とバルク リクエストの全体的なサイズに注意し、クラスターのパフォーマンスを妨げないようにする必要があります。Elastic ではバルク サイズのベンチマークを推奨しており、一般的な目安としてバルク リクエストあたり 5~15 MBです。
インデックス バッファ サイズを増やす: 未処理のインデックス作成要求のメモリ制限を、ヒープのデフォルト値の 10% 以上に増やすことができます。これは、インデックス作成が集中するワークロードに推奨されますが、メモリを大量に消費する他の操作に影響を与える可能性があります。
レプリケーションを無効にする: インデックス作成を高速化するためにレプリケーションをゼロに設定できますが、Elasticsearch がワークロードの記録システムである場合は、この方法はお勧めしません。
インプレース アップサートとデータ変更を制限する: 挿入、更新、削除を行うには、ドキュメント全体の再インデックスが必要です。CDC またはトランザクション データを Elasticsearch にストリーミングする場合は、再インデックスするデータが少なくなるため、保存するデータ量を減らすことを検討してください。
データ構造を簡素化する:ネストされたオブジェクトなどのデータ構造を使用すると、書き込みとインデックスが増加することに注意してください。フィールドの数とデータ モデルの複雑さを簡素化することで、インデックス作成を高速化できます。
クエリの実行に時間がかかりすぎる場合は、データ モデルを簡素化するか、クエリの複雑さを排除する必要がある可能性があります。考慮すべき領域をいくつか示します。
複合インデックスを作成する: 2 つの低カーディナリティ フィールドの値を結合して、簡単に検索および取得できる高カーディナリティ フィールドを作成します。たとえば、クエリでよくフィルタリングする 2 つのフィールドが郵便番号と月である場合、これらのフィールドを結合できます。
ドキュメントのカスタム ルーティングを有効にする: Elasticsearch は、すべてのシャードにクエリをブロードキャストして結果を返します。カスタム ルーティングを使用すると、データがどのシャードに存在するかを判断して、クエリの実行を高速化できます。ただし、カスタム ルーティングを採用する場合は、ホットスポットに注意する必要があります。
構造化検索にはキーワード フィールド タイプを使用します。ID や郵便番号などのコンテンツに基づいてフィルター処理する場合は、取得を高速化するために、整数タイプやその他の数値フィールド タイプではなく、キーワード フィールド タイプを使用することをお勧めします。
親子関係とネストされたオブジェクトの使用をやめる: 親子関係は、Elasticsearch の結合サポートの欠如に対する優れた回避策であり、取り込みの高速化と再インデックスの制限に役立ちます。最終的に、このアプローチでは組織はメモリ制限に達します。その場合、データの非正規化を行うことでクエリのパフォーマンスを高速化できます。
Elasticsearch のスケーリングの課題の多くは、シャーディングとインデックス作成の戦略に帰着します。シャードの数やシャードの大きさについて、すべての人に当てはまる戦略はありません。戦略を決定する最良の方法は、均一な本番ワークロードでテストとベンチマークを実行することです。考慮すべき追加のアドバイスを次に示します。
強制マージ API の使用: 強制マージ API を使用して、各シャード内のセグメント数を減らします。セグメントのマージはバックグラウンドで自動的に行われ、削除されたドキュメントは削除されます。強制マージを使用すると、古いドキュメントを手動で削除してパフォーマンスを向上させることができます。これはリソースを大量に消費する可能性があるため、使用率がピークのときには実行しないでください。
負荷の不均衡に注意してください: Elasticsearch には、シャードによるリソース使用率を把握し、シャードの配置を決定する際にそれを考慮する適切な方法がありません。その結果、ホット シャードが発生する可能性があります。この状況を回避するには、データ ノートよりも多くのシャードと、データ ノードよりも小さなシャードを持つことを検討してください。
時間ベースのインデックスを使用する: 時間ベースのインデックスを使用すると、保持期間に基づいてクラスター内のインデックスとシャードの数を減らすことができます。Elasticsearch はロールオーバー インデックス API も提供しているため、経過時間やドキュメント サイズに基づいて新しいインデックスにロールオーバーしてリソースを解放できます。
マルチテナントの最も一般的な戦略は、顧客またはテナントごとに 1 つのインデックスを持つか、カスタム ルーティングを使用することです。ワークロードに応じて戦略を比較検討する方法は次のとおりです。
顧客またはテナントごとのインデックス: 顧客ごとに個別のインデックスを構成すると、ユーザー ベースが小さく、顧客が数百から数千人いる企業や、顧客がデータを共有しない場合に適しています。また、各顧客が独自のスキーマを持ち、より高い柔軟性が必要な場合にも、顧客ごとにインデックスを作成すると便利です。
カスタム ルーティング: カスタム ルーティングを使用すると、ドキュメントが存在するシャード (顧客 ID やテナント ID など) を指定して、ドキュメントのインデックス作成時にルーティングを指定できます。特定の顧客に基づいてクエリを実行すると、クエリは顧客データを含むシャードに直接送信されるため、応答時間が短縮されます。カスタム ルーティングは、顧客間で一貫したスキーマがあり、多数の顧客がいる場合に適したアプローチです。これは、フリーミアム モデルを提供する場合によく見られます。
Elasticsearch は、ログ分析とテキスト検索のユースケース向けに設計されています。大規模なリアルタイム分析に Elasticsearch を使用する多くの組織では、クエリの複雑さやデータ取り込みの遅延を制限するなど、パフォーマンスやコスト効率を維持するためにトレードオフを行う必要があります。使用パターンを制限し始めたり、更新間隔が SLA を超えたり、結合する必要のあるデータセットを追加したりする場合は、Elasticsearch の代替品を探すことが理にかなっている可能性があります。
Rockset は代替手段の 1 つであり、リアルタイムのストリーミング データの取り込みと大規模な低レイテンシのクエリ専用に構築されています。Elasticsearchから移行する方法と、2 つのシステムのアーキテクチャの違いについて説明します。