web-dev-qa-db-ja.com

ActiveMQ:一時キューを使用しながらブローカーのフェイルオーバーを処理する方法

私のJMSアプリケーションでは、コンシューマーアプリケーションから返信を受け取ることができるように、プロデューサーの一時キューを使用しています。

このスレッドで言及されているように、私の側でもまったく同じ問題に直面しています: http://activemq.2283324.n4.nabble.com/jira-Created-AMQ-3336-Temporary-Destination-errors-on-HA -failover-in-broker-network-with-Failover-tt-td3551034.html#a3612738

ネットワークで任意のブローカーを再起動すると、一時キューに応答を送信しようとしたときに、コンシューマーアプリケーションログに次のような多くのエラーが表示されました。

javax.jms.InvalidDestinationException:
  Cannot publish to a deleted Destination: temp-queue://ID:...

それから私は使用することを示唆しているゲイリーの応答を見ました

jms.watchTopicAdvisories=false

クライアントのURLパラメータとしてbrokerURL。この追加パラメーターを使用して、クライアントブローカーのURLをすぐに変更しました。ただし、このフェイルオーバーテストのためにネットワークでブローカーを再起動すると、次のようなエラーが表示されます。

javax.jms.JMSException: 
  The destination temp-queue:
    //ID:client.Host-65070-1308610734958-2:1:1 does not exist.

ActiveMQ 5.5バージョンを使用しています。クライアントブローカーのURLは次のようになります。

failover:(tcp://amq-Host1:61616,tcp://amq-Host2.tred.aol.com:61616,tcp://amq-Host3:61616,tcp://amq-Host4:61616)?jms.useAsyncSend=true&timeout=5000&jms.watchTopicAdvisories=false

さらに、4つのブローカーの1つに対する私のactivemq構成XMLは次のとおりです。 amq1.xml

ここの誰かがこの問題を調べて、この設定で私が犯している間違いを教えてください。

更新:

コードでリクエスト/レスポンスをどのように行っているかをさらに明確にするには:

  1. 私はすでにプロデューサーごとの宛先(つまり、一時キュー)を使用しており、これをすべてのメッセージの返信先ヘッダーに設定します。
  2. JMSCorrelationIDヘッダーでメッセージごとの一意の相関識別子を既に送信しています。
  3. 私の知る限り、CamelとSpringでも、要求と応答のメカニズムに一時キューを使用しています。唯一の違いは、Spring JMS実装はすべてのメッセージの一時キューを作成および破棄するのに対し、私はプロデューサーの存続期間に一時キューを作成することです。この一時キューは、クライアント(プロデューサー)アプリがシャットダウンしたとき、またはAMQブローカーがこの一時キューに接続されているアクティブなプロデューサーがないことを認識したときに破棄されます。
  4. メッセージがキューに長時間(60秒)保持されないように、プロデューサー側で各メッセージにメッセージの有効期限を設定しています。
52
anubhava

ブローカー属性org.Apache.activemq.broker.BrokerService#cacheTempDestinationsがあり、フェイルオーバーに役立ちます:ケース。 xml設定でこれをtrueに設定すると、クライアントの接続が切断されても一時宛先はすぐには削除されません。高速フェイルオーバー:再接続すると、一時キューから再びプロデューサーまたはコンシューム(あるいはその両方)が可能になります。

キャッシュの削除を処理するtimeBeforePurgeTempDestinations(デフォルトは5秒)に基づくタイマータスクがあります。

ただし、1つの注意点があります。activemq-coreには、その属性を使用するテストが見当たらないため、このテストについて保証することはできません。

25
gtully

一時的なキューは、要求/応答シナリオのリクエスター(プロデューサー)が接続するブローカーで作成されます。これらはjavax.jms.Sessionから作成されるため、セッションが切断されると、クライアントの切断またはブローカーの障害/フェイルオーバーにより、これらのキューは永久に失われます。他のブローカーは、いずれかのコンシューマーがそれらのキューに応答しようとしたときに何が意味されるのか理解しません。したがって、あなたの例外。

これには、フェイルオーバーに対処し、すべてのメッセージを永続化することを想定し、アーキテクチャの考え方を変える必要があります。問題を攻撃する一般的な方法は次のとおりです。

  1. 返信先ヘッダーは、リクエスタープロセスに固有のキューを参照する必要があります。 queue:response.<client id>。クライアントの数が限られている場合はクライアントIDが標準名になる可能性があり、クライアントの数が多い場合はUUIDになる可能性があります。
  2. アウトバウンドメッセージは相関識別子を設定する必要があります(要求を応答に関連付けることができる文字列です-要求者は結局同時に複数の要求を行う可能性があります)。これはJMSCorrelationIDヘッダーで設定され、リクエストからレスポンスメッセージにコピーされます。
  3. リクエスタは、その相関IDに基づいてメッセージボディを要求元のスレッドに返すリスナーをそのキューに設定する必要があります。おそらく、Futureを介して、相関IDと元のスレッドのマップのようなものを手動で管理する必要があるため、このために作成する必要があるマルチスレッドコードがいくつかあります。

これは、 Apache Camelメッセージングでの要求と応答 に対して行うアプローチと同様です。

注意すべきことの1つは、クライアントが削除してもキューが消えないことです。そのため、応答メッセージが存続する時間を設定して、消費されていない場合はブローカーから削除されるようにしてください。未使用メッセージのバックログ。 期限切れのメッセージを自動的に破棄するデッドレターキュー戦略 も設定する必要があります。

9
Jakub Korab