メッセージングに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万のメッセージをどのように処理するかによって、メッセージやパフォーマンスを失うことなく、各メッセージが再試行される機会が均等になります。
私が持っている環境の範囲内で解決策を探しています。