EventProcessorHostとIEventProcessorクラスを使用して、EventHubからイベントを受信しています(MyEventProcessorと呼びます)。両方のサーバーでEPHを実行し、同じConsumerGroupを使用して(マシン名を使用して)一意のhostNameを使用してハブに接続することにより、これを2台のサーバーにスケールアウトします。
問題は次のとおりです。昼夜のランダムな時間に、アプリはこれをログに記録します。
Exception information:
Exception type: ReceiverDisconnectedException
Exception message: New receiver with higher Epoch of '186' is created hence current receiver with Epoch '186' is getting disconnected. If you are recreating the receiver, make sure a higher Epoch is used.
at Microsoft.ServiceBus.Common.ExceptionDispatcher.Throw(Exception exception)
at Microsoft.ServiceBus.Common.Parallel.TaskHelpers.EndAsyncResult(IAsyncResult asyncResult)
at Microsoft.ServiceBus.Messaging.IteratorAsyncResult`1.StepCallback(IAsyncResult result)
この例外は、LeaseLostExceptionと同時に発生し、MyEventProcessorのCloseAsyncメソッドがチェックポイントを試みたときにスローされます。 (おそらくReceiverDisconnectedExceptionのためにCloseが呼び出されていますか?)
これは、複数のマシンにスケールアウトする際のEvent Hubsの自動リース管理が原因で発生していると思います。しかし、私はそれをよりきれいに機能させ、これらの例外を回避するために別のことをする必要があるかどうか疑問に思っていますか?例:エポックのあるもの?
[〜#〜] tldr [〜#〜]:この動作はまったく正常です。
リース管理を円滑かつ例外なく行うことができない理由:開発者に状況をより詳細に制御するため。
本当に長い話-基本からの道のりEventProcessorhost
(これによりEPH
-は、 __consumer_offset topic
はKafka Consumers
に対して行います(パーティションの所有権とチェックポイントストア)はMicrosoft Azure EventHubs
チーム自身によって記述され、EventHubs partition receiver Gu
のすべてを単純なonReceive(Events)
コールバックに変換します。
EPH
は、EventHubs
のような高スループットのパーティション化されたストリームからの読み取り中に、2つの一般的な主要な既知の問題に対処するために使用されます。
フォールトトレラントな受信パイプライン-例:単純なバージョンの問題-PartitionReceiver
を実行しているホストが停止して復帰した場合-元の場所から処理を再開する必要があります。最後に正常に処理されたEventData
を記憶するために、EPH
はblob
コンストラクターに提供されたEPH
を使用してチェックポイントを格納します-ユーザーがcontext.CheckpointAsync()
。最終的に、ホストプロセスが停止すると(例:突然再起動するか、ハードウェアの障害に遭遇し、決して/カムバックしません)-すべてのEPH
インスタンスがこのタスクを受け取り、そのCheckpoint
から再開できます。
EPH
インスタンス間でパーティションのバランスをとる/分散する-たとえば、10個のパーティションと2つのEPH
インスタンス処理イベントがある場合これら10個のパーティションから-インスタンス間でパーティションを分割する方法が必要です(PartitionManager
ライブラリのEPH
コンポーネントがこれを行います)。これを実装するには、Azure Storage - Blob LeaseManagement-feature
を使用します。バージョン 2.2.10
-問題を簡単にするために、EPH
はすべてのパーティションが均等にロードされると想定します。
これで、何が起こっているのかを確認してみましょう:まず、上記の10
イベントハブパーティションと2
EPH
インスタンスがそこからイベントを処理する例を見てみましょう。
EPH
インスタンス-EPH1
が最初に起動し、単独で起動の一部であるとしましょう。10個のパーティションすべてにレシーバーを作成し、イベントを処理しています。起動時に、EPH1
は、これらの10
イベントハブパーティションを表す10
ストレージBLOBのリースを取得することにより、これらすべての10
パーティションを所有していることを通知します(標準nomenclature
- EPH
がストレージアカウントで内部的に作成するもの-StorageConnectionString
からctor
に渡されます)。リースは 設定された時間で取得 となり、その後、EPH
インスタンスはこのパーティションの所有権を失います。EPH1
継続的にannounces
がたまにrenewing
によって、これらのパーティションをまだ所有している-renewal
によってBLOBがリースされます。 PartitionManagerOptions
の頻度は、他の有用なチューニングとともに、 AzureStorageAccount
を使用して実行できます。EPH2
が起動し、EPH1
と同じctor
をEPH2
のEPH
にも提供したとします。現在、処理する0
パーティションがあります。したがって、download
インスタンス間でパーティションのバランスを達成するために、それは先に進み、leaseblobs
owner
から_へのマッピングを持つすべてのpartitionId
のリスト[$ var] _。これから、それはSTEAL
の公平な配分のためにpartitions
leasesになります-これは5
ですこの例では、そのlease blob
に関する情報を発表します。この一部として、EPH2
はPartitionX
によって書き込まれた最新のチェックポイントを読み取り、リースを盗み取り、先に進み、対応するPartitionReceiver
をEpoch
と同じに作成します。 Checkpoint
の1つとして。EPH1
はこれら5つのpartitions
の所有権を失い、現在の状態に基づいてさまざまなエラーが発生します。EPH1
が実際にPartitionReceiver.Receive()
呼び出しを呼び出している場合-EPH2
が同じレシーバーでPartitionReceiver
を作成している場合-EPH1
が発生します ReceiverDisconnectedException 。これにより、最終的にIEventProcessor.Close(CloseReason=LeaseLost)
が呼び出されます。受信されるメッセージが大きい場合、またはPrefetchCount
が小さい場合、この特定の例外にヒットする可能性が高くなることに注意してください。どちらの場合も、レシーバーはより積極的なI/Oを実行します。EPH1
がcheckpointing
the lease
またはrenewing
the lease
の状態の場合、EPH2
stole
リース、EventProcessorOptions.ExceptionReceived
eventHandlerはleaselostException
(leaseblob
での409
競合エラーとともに)で通知されます-これは最終的にIEventProcess.Close(LeaseLost)
。リース管理を円滑かつ例外なく行うことができない理由:
コンシューマをシンプルでエラーのない状態に保つために、リース管理関連の例外がEPH
によって飲み込まれ、ユーザーコードにまったく通知されない可能性があります。ただし、LeaseLostException
をスローすると、IEventProcessor.ProcessEvents()
コールバックで興味深いバグを発見できるようになる可能性があることに気づきました-症状は次のとおりです-パーティションの頻繁な移動
EPH1
はrenew
のリースに失敗し、復旧します。 -そして、このマシンのn/wが1日間不安定であると想像してみてください-EPH
インスタンスがping-pong
をPartitions
と再生します!このマシンは、他のマシンからリースを継続的に盗もうとします-これはEPH
の観点からは正当ですが、EPH
のユーザーにとっては完全な障害であるため、完全な災害です処理パイプ付き。 EPH
-n/wがこの不安定なm/cに戻ったとき、ReceiverDisconnectedException
が正確に表示されます。私たちは、開発者がこれを嗅ぐことを可能にすることが最善で実際的な唯一の方法であると考えています!ProcessEvents
ロジックにバグがある-致命的な未処理の例外をスローし、プロセス全体を停止させるような単純なシナリオ-例:有害イベント。このパーティションは頻繁に移動します。EPH
も使用しているのと同じストレージアカウントで書き込み/削除操作を実行しているお客様-誤って(自動クリーンアップスクリプトなど)など。EventHub.Partition
が配置されているAzure d.cで5分outage
と言ってください。パーティションはEPH
インスタンス間を移動します。基本的に、ほとんどの状況で、差分を検出するのは難しいでしょう。これらのシチュエーションとバランシングによる正当なleaseLostの間で、これらのシチュエーションの制御を開発者に委任したいと考えています。