大量のデザインを再試行


8

メッセージングにActiveMQを使用するJavaシステムがあります。また、システムは1秒間に約400から600のトランザクションを処理し、すべてがスムーズに実行されていても問題はありません。システムは、これらのトランザクションを外部システムに送信する必要もあります。

外部システムが長時間(たとえば1〜2時間)ダウンしている場合、私たちが行うことは、キューの停止中に外部システムに正常に送信されなかった失敗したメッセージ(再試行キューと呼ばれるもの)をドロップすることです。 。

これらのメッセージをタイムリーに処理して、外部システムに回復する十分な時間を与える必要があります。

私たちはいくつかのアプローチを試みましたが、どれも完全に機能するようには見えません。それらのほとんどは、処理するメッセージの数が少ない場合に機能します。

アプローチ#1: JMSヘッダーにタイムスタンプを設定するActiveMQ遅延を使用しました(詳細については、こちらをご覧ください:http : //activemq.apache.org/delay-and-schedule-message-delivery.html)。キューには数百または数千のメッセージがあります。

50万件以上のメッセージがあると、メッセージが失われることがわかりました。

たとえば、2万通のメッセージでもメッセージが消えたことがわかります。

メッセージが1時間に最大12回試行されるように、遅延を5分に設定しました。外部システムが1時間ダウンしたとき、すべての20kメッセージが少なくとも12回再試行されると予想しました。

5分ごとに消費すると、次のことがわかりました。

試行1:20kメッセージ試行2:20kメッセージ

試行7:19987メッセージ試行10:19960メッセージ試行12:19957メッセージ

時々、すべての2万通のメッセージが処理されましたが、テスト結果に一貫性がありませんでした。

アプローチ#2:

ActiveMQの再配信ポリシーを使用しました。接続ファクトリレベルでポリシーを設定し、セッションを処理し、外部システムがダウンしているときに例外をスローするため、ブローカーは再配信ポリシーの設定に基づいてメッセージを再配信し続けます。このアプローチも、停止がより長く続く場合にはうまく機能せず、ノンブロッキングのコンシューマーを用意する必要はありません。ディスパッチキューレベル自体で機能し、着信トランザクションが多い場合はキューに負担をかけます。

アプローチ#3:

X分ごとに起動するQuartzスケジューラーを使用して接続を作成し、コンシューマーが再試行キューからメッセージを取得してさらに処理を試み、外部システムがまだダウンしている場合は、失敗したメッセージをキューの後ろに置きます。このアプローチには多くの問題があり、接続や消費者などを管理する必要がありました。

たとえば、キュ​​ーにメッセージが2つある場合、メッセージの数よりも多くのコンシューマーがあると、メッセージがコンシューマーによってピックアップされ、同じコンシューマーがメッセージを再試行にドロップします(外部システムはまだダウンしています)、別のコンシューマーがそれをピックアップしているため、コンシューマーとブローカーの間でメッセージが行き来します。

アプローチ#4:

失敗したメッセージのDBへの保存を試み、QスケジューラーをX分ごとに実行して、DBからメッセージを取得しました。

これは最適化されていないだけでなく、複数のノードで実行されているDBコンシューマとDBの間の多くのトランザクションチェックが含まれます。

私の環境は、Java、JBoss、ActiveMQ 5.9、MySQL 5.6およびSpring 3.2です。

再試行テンプレート(Springから)やJava 7/8での非同期再試行パターンなど、他のいくつかのアプローチを実行しました

この問題についての私の見解は、ほとんどのソリューションは最小の負荷がかかっているときに機能し、停止が長く続くか、メッセージの量が本当に多いときに壊れるように見えるということです。

失敗したメッセージを保存して転送できる場所を探しています。400 TPSシステムの場合、1時間で144万のメッセージが届く可能性があります。

外部システムがダウンしている場合は、これらの144万のメッセージをどのように処理するかによって、メッセージやパフォーマンスを失うことなく、各メッセージが再試行される機会が均等になります。

私が持っている環境の範囲内で解決策を探しています。

回答:


1

ここでの問題はスロットルにあります。システムが立ち上がったら、アプリケーションはパブリッシャーとコンシューマーの両方に負担がかからないように設計する必要があります。

アルゴリズムを巧みに使うことができます。メッセージを優先度で分類する機能がある場合、失敗したメッセージはより低い優先度で保存できます。そのため、パブリッシャーは新しいメッセージをパブリッシュした後、優先度の低いキューを調べて、失敗したメッセージを再パブリッシュする必要があるかどうかを確認し、再パブリッシュできます。

これは、メッセージを抑制するよく知られた方法の1つです。特定のニーズに基づいて、ここで適用できる他のスロットルアルゴリズムがあると思います。


0

以下は、各ノードにメッセージキューがあり、これらのすべてのノードが1つのDBを使用していることを前提としています。これらのノードはすべて、1つの外部システムにメッセージを送信しようとしています。

3番目のアプローチを少し変更するとうまくいく場合があります。

  1. ノードが起動すると、外部システムがダウンした場合に備えて、新しいメッセージのみを格納するテーブルを作成します。たとえば、node1がメッセージを格納するmessages_node1テーブルを作成したとします。

ここでのユースケースは、3つのノードが実行されているすべての外部システムが突然ダウンした場合、各ノードはMQにエンキューするのではなく、対応するテーブルに新しく到着するメッセージを格納する必要があります。配信されていないメッセージをキュー自体に保持します。外部システムが回復にかかると、既存のメッセージングキューは読み込まれません。ノードが外部システムが起動していることを認識したら、対応するテーブルからメッセージのエンキューを開始します。

このアプローチは多くの問題を解決します1.外部システムの復旧時間に依存しません 3.ノードごとに独自のテーブルがあるため、ノード間の競合が最小限に抑えられます。4.メッセージの順序はある程度保持されます。

これらのイベントをトリガーするAPIを作成できます。上記のアプローチの返信での修正

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.