OpenSearch サービスで検索拒否または書き込み拒否を解決する方法を教えてください。
Amazon OpenSearch Service クラスターに検索または書き込みリクエストを送信すると、そのリクエストは拒否されます。
簡単な説明
OpenSearch Service クラスターでデータを書き込んだり、検索したりすると、次の HTTP 429 エラーまたは es_rejected_execution_exception が表示されることがあります。
error":"elastic: Error 429 (Too Many Requests): rejected execution of org.elasticsearch.transport.TransportService$7@b25fff4 on EsThreadPoolExecutor[bulk, queue capacity = 200, org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor@768d4a66[Running, pool size = 2, active threads = 2, queued tasks = 200, completed tasks = 820898]] [type=es_rejected_execution_exception]" Reason={"type":"es_rejected_execution_exception","reason":"rejected execution of org.elasticsearch.transport.TcpTransport$RequestHandler@3ad6b683 on EsThreadPoolExecutor[search, queue capacity = 1000, org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor@bef81a5[Running, pool size = 25, active threads = 23, queued tasks = 1000, completed tasks = 440066695]]"
以下の変数が HTTP 429 エラーまたは es_rejected_execution_exception の原因となる可能性があります。
- データノードインスタンスタイプと検索または書き込み制限
- インスタンスメトリックの値が高い
- アクティブスレッドとキュースレッド
- 高い CPU 使用率と JVM メモリ圧力
HTTP 429 エラーは、クラスターへの検索および書き込みリクエストが原因で発生する可能性があります。拒否は、クラスターの単一ノードまたは複数のノードから発生することもあります。
注:Elasticsearch のバージョンが異なれば、_index API への呼び出し処理に使うスレッドプールも異なります。Elasticsearch バージョン 1.5 と 2.3 はインデックススレッドプールを使用します。Elasticsearch バージョン 5.x、6.0、6.2 ではバルクスレッドプールを使用します。Elasticsearch バージョン 6.3 以降では、書き込みスレッドプールを使用します。詳細については、Elasticsearch ウェブサイトの スレッドプール を参照してください。
解決方法
データノードインスタンスタイプと検索または書き込み制限
データノードインスタンスタイプには固定仮想 CPU (vCPU) があります。vCPU 数を計算式に代入すると、ノードがキューに入る前にノードが実行できる同時検索または書き込み操作が得られます。アクティブなスレッドがいっぱいになると、そのスレッドはキューに流出し、最終的に拒否されます。vCPU とノードタイプの関係についての詳細は、OpenSearch Service の料金表 を参照してください。
さらに、ノードごとに実行できる検索数またはノードあたりの書き込み数には制限があります。この制限は、スレッドプールの定義と Elasticsearch のバージョン番号に基づいています。詳細については、Elasticsearch ウェブサイトの スレッドプール を参照してください。
たとえば、Elasticsearch クラスター (バージョン 7.4) の 5 つのノードに R5.2xlarge ノードタイプを選択した場合、そのノードには 8 つの vCPU が割り当てられます。
次の式を使用して、検索リクエストの最大アクティブスレッド数を計算します。
int ((# of available_processors * 3) / 2) + 1
次の式を使用して、書き込み要求の最大アクティブスレッド数を計算します。
int (# of available_processors)
R5.2xlarge ノードでは、最大 13 の検索操作を実行可能です。
(8 VCPUs * 3) / 2 + 1 = 13 operations
R5.2xlarge ノードでは、最大 8 つの書き込み操作を実行可能です。
8 VCPUs = 8 operations
5 つのノードで構成される OpenSearch Service クラスターでは、最大 65 の検索操作を実行可能です。
5 nodes * 13 = 65 operations
5 つのノードで構成される OpenSearch Service クラスターでは、最大 40 の書き込み操作を実行可能です。
5 nodes * 8 = 40 operations
インスタンスメトリックの値が高い
429 例外のトラブルシューティングを行うには、クラスターの次の Amazon CloudWatch メトリックを確認してください。
- IndexingRate:1 分あたりのインデックス処理数。2 つのドキュメントを追加して 2 つの更新を行う_bulk API を 1 回呼び出すと、ノード全体に分散する可能性のある 4 つの操作としてカウントされます。そのインデックスに 1 つ以上のレプリカがある場合、クラスター内の他のノードも合計 4 回のインデックス処理を記録します。ドキュメントの削除は IndexingRate メトリックにはカウントされません。
- SearchRate:データノード上のすべてのシャードの 1 分あたりの検索リクエストの合計数。_search API を 1 回呼び出すだけで、さまざまなシャードの結果が返される可能性があります。1 つのノードに 5 つの異なるシャードがある場合、クライアントが 1 回しかリクエストしなかった場合でも、ノードはこのメトリックについて「5」を報告します。
- **CoordinatingWriteRejected:**調整ノードで発生した拒否の総数。これらの拒否は、OpenSearch Service の起動以降に蓄積されたインデックス作成圧力が原因です。
- **PrimaryWriteRejected:**プライマリシャードで発生した拒否の総数。これらの拒否は、前回の OpenSearch Service の起動以降に蓄積されたインデックス作成圧力が原因です。
- **ReplicaWriteRejected:**インデックス作成圧力が原因でレプリカシャードで発生した拒否の総数。これらの拒否は、前回の OpenSearch Service の起動以降に蓄積されたインデックス作成圧力が原因です。
- **ThreadpoolWriteQueue:**書き込みスレッドプール内のキューに入っているタスクの数。このメトリックは、リクエストが拒否されているのは、CPU 使用率が高いためなのか、インデックス作成の同時実行性が高いためなのかを示しています。
- **ThreadpoolWriteRejected:**書き込みスレッドプールで拒否されたタスクの数。
**注:**OpenSearch Service バージョン 7.9 では、デフォルトの書き込みキューサイズが 200 から 10,000 に増加しています。そのため、OpenSearch Service から拒否を示される指標は、もはや、このメトリックだけではなくなりました。バージョン 7.9 以降での拒否を監視するには、CoordinatingWriteRejected、PrimaryWriteRejected、および ReplicaWriteRejected メトリックを使用してください。 - **ThreadpoolSearchQueue:**検索スレッドプール内のキューに入っているタスクの数。キューのサイズが常に大きい場合は、クラスターのスケーリングを検討してください。検索キューの最大サイズは 1,000 です。
- **ThreadpoolSearchRejected:**検索スレッドプールで拒否されたタスクの数。この数が増え続ける場合は、クラスターのスケーリングを検討してください。
- **JVMMemoryPressure:**JVM のメモリ負荷は、クラスターノード内の Java ヒープの割合を指定します。JVM のメモリ負荷が 75% に達すると、OpenSearch Service はコンカレントマークスイープ (CMS) ガベージコレクタを開始します。ガベージコレクションは CPU に大きな負荷がかかるプロセスです。JVM のメモリ負荷が数分間この割合にとどまると、クラスターのパフォーマンスに関する問題が発生する可能性があります。詳細については、「Amazon OpenSearch Service クラスターで高い JVM メモリ負荷のトラブルシューティングはどうやればよいですか?」を参照してください。
**注:**一覧表示されているスレッドプールのメトリックは、IndexingRate と SearchRate について知るのに役立ちます。
CloudWatch で OpenSearch サービスクラスターをモニタリングする方法の詳細については、インスタンスメトリックを参照してください。
アクティブスレッドとキュースレッド
CPU が不足していたり、リクエストの同時実行数が多いと、キューがすぐにいっぱいになり、HTTP 429 エラーが発生する可能性があります。キューのスレッドを監視するには、CloudWatch の ThreadPoolSearchQueue と ThreadPoolWriteQueue のメトリックを確認してください。
アクティブスレッドとキュースレッドに検索が拒否されていないかどうかを確認するには、次のコマンドを使用します。
GET /_cat/thread_pool/search?v&h=id,name,active,queue,rejected,completed
アクティブスレッドとキュースレッドの書き込み拒否を確認するには、「search」を「write」に置き換えます。出力の拒否値と完了値は累積ノードカウンタであり、新しいノードが起動されるとリセットされます。詳細については、Elasticsearch ウェブサイトの cat スレッドプール API の「明示列を使用する例」セクションを参照してください。
**注:**各ノードのバルクキューでは、使用している Elasticsearch のバージョンに応じて、50 から 200 のリクエストを処理することができます。キューがいっぱいになると、新しいリクエストは拒否されます。
検索および書き込み拒否のエラー
検索拒否
検索拒否エラーは、アクティブなスレッドがビジー状態で、キューが最大数のタスクまでいっぱいになっていることを示しています。その結果、検索リクエストが拒否される可能性があります。OpenSearch Service のログを設定すれば、これらのエラーメッセージが検索スローログに表示されるようにすることができます。
**注:**余分なオーバーヘッドを避けるには、スローログのしきい値を余裕を持って設定してください。たとえば、ほとんどのクエリが 11 秒かかり、しきい値が「10」の場合、OpenSearch Service はログを書き込むのにさらに時間がかかります。スローログのしきい値を 20 秒に設定することで、このオーバーヘッドを回避できます。そうすると、(11 秒以上かかる) 遅いクエリのごく一部のみがログに記録されます。
検索スローログを CloudWatch にプッシュするようにクラスターを設定したら、スローログ生成のしきい値を特定のしきい値に設定してください。次の HTTP POST 呼び出しを使用して、ログ生成速度を低下させる特定のしきい値を設定することができます。
curl -XPUT http://<your domain’s endpoint>/index/_settings -d '{"index.search.slowlog.threshold.query.<level>":"10s"}'
書き込み拒否
書き込み拒否としての 429 エラーメッセージは、バルクキューエラーを示しています。es_rejected_execution_exception[bulk] は、キューがいっぱいで、新しいリクエストが拒否されたことを示します。このバルクキューエラーは、クラスターへのリクエストの数がバルクキューサイズ (threadpool.bulk.queue_size) を超えた場合に発生します。各ノードのバルクキューでは、使用している Elasticsearch のバージョンに応じて、50 から 200 のリクエストを処理できます。
OpenSearch Service のログを設定して、これらのエラーメッセージがインデックススローログに表示されるようにすることができます。
**注:**余分なオーバーヘッドを避けるには、スローログのしきい値を余裕を持って設定してください。たとえば、ほとんどのクエリが 11 秒かかり、しきい値が「10」の場合、OpenSearch Service はログの書き込みにさらに時間がかかります。スローログのしきい値を 20 秒に設定することで、このオーバーヘッドを回避できます。そうすると、(11 秒以上かかる) 遅いクエリのごく一部のみがログに記録されます。
検索スローログを CloudWatch にプッシュするようにクラスターを設定したら、スローログ生成のしきい値を特定のしきい値に設定してください。ログ生成が遅くなる特定のしきい値を設定するには、次の HTTP POST 呼び出しを使用します。
curl -XPUT http://<your domain’s endpoint>/index/_settings -d '{"index.indexing.slowlog.threshold.query.<level>":"10s"}'
書き込み拒否のベストプラクティス
書き込み拒否を軽減するベストプラクティスをいくつか紹介します。
- ドキュメントのインデックス作成が速くなると、書き込みキューが容量に達する可能性が低くなります。
- ワークロードと必要なパフォーマンスに応じてバルクサイズを調整してください。詳細については、Elasticsearch ウェブサイトのインデックス作成速度の調整を参照してください。
- アプリケーションロジックに指数関数的再試行ロジックを追加します。指数関数的再試行ロジックにより、失敗したリクエストは自動的に再試行されます。
**注:**クラスターで継続的に大量の同時リクエストが発生する場合、指数関数的再試行ロジックは 429 エラーの解決に役立ちません。このベストプラクティスは、トラフィックが突然または不定期に急増するときに使ってください。 - Logstash からデータを取り込む場合は、ワーカー数とバルクサイズを調整してください。バルクサイズは 3 ~ 5 MB に設定するのがベストプラクティスです。
インデックス作成のパフォーマンスチューニングの詳細については、「OpenSearch Service クラスターのインデックス処理パフォーマンスを向上させるにはどうすればよいですか?」を参照してください。
検索拒否のベストプラクティス
検索拒否を軽減するベストプラクティスをいくつか紹介します。
- より大きなインスタンスタイプに切り替えます。OpenSearch Service で検索結果を高速にするには、ファイルシステムのキャッシュに大きく依存します。検索リクエスト用の各ノードのスレッドプール内のスレッド数は、int((# of available_processors * 3) / 2) + 1 です。vCPU の数が多いインスタンスに切り替えると、検索リクエストを処理するスレッドが増えます。
- 特定のインデックス、または妥当な閾値を持つすべてのインデックスの検索スローログをオンにします。どのクエリの実行に時間がかかっているかを確認し、クエリの検索パフォーマンス戦略を導入してください。詳細については、「Elasticsearch 検索のトラブルシューティング (初心者向け)」または「高度なチューニング」を参照してください。 Elasticsearch ウェブサイトで低速な Elasticsearch クエリを見つけて修正します。