Azure Event Hubs イベント プロセッサーのトラブルシューティング

この記事では、EventProcessorClient 型を使用する際に発生する場合がある一般的な問題の解決策について説明します。 Azure Event Hubs の使用時に発生する可能性がある他の一般的な問題の解決策については、「Azure Event Hubs のトラブルシューティング」を参照してください。

イベント プロセッサーを使用する場合の 412 の前提条件エラー

412 前提条件エラーは、クライアントがパーティションの所有権を取得または更新しようとしたが、所有権レコードのローカル バージョンが古い場合に発生します。 この問題は、別のプロセッサー インスタンスがパーティションの所有権を盗んだ場合に発生します。 詳細については、次のセクションを参照してください。

パーティションの所有権の変更が頻繁に発生する

EventProcessorClient インスタンスの数が変わると (追加または削除されると)、実行中のインスタンスは、インスタンス間の負荷分散パーティションを試行します。 プロセッサー数が変わってから数分間は、パーティションの所有者が変わることが予想されます。 バランスが取れた後は、パーティションの所有権が安定し、変更頻度が低くなります。 プロセッサー数が一定のときにパーティションの所有権が頻繁に変更される場合は、何か問題があることを示しています。 GitHub の問題にログと再現ファイルを添付することが推奨されます。

パーティションの所有権は、CheckpointStore の所有権レコーダー経由で決定されます。 負荷分散間隔ごとに、EventProcessorClient は、次のタスクを実行します。

  1. 最新の所有権レコーダーをフェッチします。
  2. パーティション所有権の有効期限内にタイムスタンプが更新されていないレコードを確認するには、レコードを確認します。 この条件に一致するレコードのみが考慮されます。
  3. 未所有のパーティションがあり、負荷が EventProcessorClient インスタンス間で分散されていない場合、イベント プロセッサー クライアントはパーティションの要求を試行します。
  4. そのパーティションへのアクティブなリンクを持つ、所有しているパーティションの所有権レコードを更新します。

次の一覧で説明するように、EventProcessorClientBuilder 経由で EventProcessorClient を作成する際は、負荷分散と所有権の有効期限間隔を構成できます。

たとえば、所有権レコードが午前 9 時 30 分に更新され、partitionOwnershipExpirationInterval が 2 分の場合です。 負荷分散サイクルが発生し、最後の 2 分間または午前 9 時 32 分までに所有権レコードが更新されていないことに気付いた場合、パーティションは未所有と見なされます。

パーティション コンシューマーの 1 つでエラーが発生した場合、対応するコンシューマーは閉じられますが、次の負荷分散サイクルまで解放を試みることはありません。

"...current receiver '<RECEIVER_NAME>' with epoch '0' が切断されています"

エラー メッセージ全体が次の出力のようになっていることを確認します。

New receiver 'nil' with higher epoch of '0' is created hence current receiver 'nil' with epoch '0'
is getting disconnected. If you are recreating the receiver, make sure a higher epoch is used.
TrackingId:&lt;GUID&gt;, SystemTracker:&lt;NAMESPACE&gt;:eventhub:&lt;EVENT_HUB_NAME&gt;|&lt;CONSUMER_GROUP&gt;,
Timestamp:2022-01-01T12:00:00}"}

このエラーは、EventProcessorClient インスタンスの追加または削除後に負荷分散が発生した場合に発生します。 負荷分散は進行中のプロセスです。 コンシューマーと共に (既定では) 30 秒おきに BlobCheckpointStore を使用すると、コンシューマーは各パーティションに対する要求を持つコンシューマーを確認し、いくつかのロジックを実行して、別のコンシューマーからパーティションを「盗む」必要があるかどうかを判断します。 パーティションの排他的所有権をアサートするために使用されるサービス メカニズムは、エポックと呼ばれます。

ただし、インスタンスが追加または削除されていない場合は、根本的な問題に対処する必要があります。 詳細については、「パーティション所有権変更頻度」セクションと「GitHub 問題のファイリング」を参照してください。

CPU 使用率が高い

CPU 使用率が高いのは、通常、インスタンスが所有するパーティションが多すぎるためです。 CPU コアごとに 3 つ以下のパーティションを使用することをお勧めします。 CPU コアごとに 1.5 個のパーティションから始めて、所有するパーティションの数を増やすことでテストすることをお勧めします。

メモリ不足とヒープ サイズの選択

JVM の現在の最大ヒープがアプリケーションの実行に不十分な場合、メモリ不足 (OOM) の問題が発生する可能性があります。 アプリケーションのヒープ要件を測定することもできます。 次に、結果に基づいて、-Xmx JVM オプションを使用して適切な最大ヒープ メモリを設定してヒープのサイズを変更します。

ホスト (VM またはコンテナー) に対して使用可能なメモリまたは制限セット (コンテナーの構成で要求されたメモリなど) より大きい値として -Xmx を使用しないでください。 ホストが Java ヒープをサポートするのに十分なメモリを割り当てる必要があります。

次の手順では、最大 Java ヒープ値を測定する一般的な方法について説明します。

  1. 運用環境に近い環境でアプリケーションを実行します。この環境では、運用環境で予想されるピーク負荷下でアプリケーションがイベントを送信、受信、および処理します。

  2. アプリケーションが安定した状態になるまで待機します。 この段階では、アプリケーションと JVM によって、すべてのドメイン オブジェクト、クラス型、静的インスタンス、オブジェクト プール (TCP、DB 接続プール) が読み込まれます。

    安定状態では、次のスクリーンショットに示すように、ヒープ コレクションの安定した sawtooth-shaped パターンが表示されます。

    Screenshot of the heap memory collection showing the stable sawtooth pattern.

  3. アプリケーションが安定した状態になったら、JConsole などのツールを使用して完全ガベージ コレクション (GC) を強制します。 完全な GC の後に占有されているメモリを確認します。 完全な GC の後に 30% のみが占有されるようにヒープのサイズを設定する必要があります。 この値を使用して、最大ヒープ サイズ (-Xmx を使用) を設定できます。

コンテナーを使用している場合は、JVM インスタンスのヒープ以外のニーズに対して最大 1 GB のメモリを追加するようにコンテナーのサイズを変更します。

プロセッサー クライアントが受信を停止する

プロセッサー クライアントは、多くの場合、ホスト アプリケーションで何日間も継続的に実行されます。 場合によっては、EventProcessorClient が 1 つ以上のパーティションを処理していないことが分かります。 通常、例外が発生した理由を判断するのに十分な情報がありません。 EventProcessorClient 停止は、一過性のエラーから回復しようとして発生した根本的な原因 (つまりレース状態) の症状です。 必要な情報については、「GitHubの問題 のファイリング」を参照してください。

プロセッサーの再起動時に受信した EventData の重複

EventProcessorClient および Event Hubs サービスは、少なくとも 1 回の配信が保証されます。 メタデータを追加して、重複するイベントを識別できます。 詳細については、Stack Overflow の「Azure Event Hubs は少なくとも 1 回の配信を保証しますか?」を参照してください。 配信は1 回のみでよい場合、クライアントからの受信確認を待つ Service Bus を検討する必要があります。 メッセージング サービスの比較については、「Azure メッセージング サービスの選択」を参照してください。

レガシーから新しいクライアント ライブラリに移行する

「移行ガイド」には、レガシー クライアントからの移行と従来のチェックポイントの移行に関する手順が含まれています。

次のステップ

この記事のトラブルシューティング ガイダンスが、Azure SDK for Java クライアント ライブラリを使用するときの問題の解決に役立たない場合は、Azure SDK for Java GitHub リポジトリ問題を提出することをお勧めします。