web-dev-qa-db-ja.com

JMS接続、セッション、プロデューサー/コンシューマー間の関係

20kのJMSメッセージのバッチを同じキューに送信したい。 10個のスレッドを使用してタスクを分割しているため、それぞれが2kのメッセージを処理します。トランザクションは必要ありません。

1つの接続、1つのセッション、10のプロデューサーが推奨される方法かどうか疑問に思っていましたか?

すべてのスレッドで1つのプロデューサーを共有している場合はどうなりますか?メッセージが破損しているか、同期して送信されますか(パフォーマンスは向上しません)?

常に同じキューに接続している場合、新しい接続またはセッションを作成するかどうかを決定する一般的なガイドラインは何ですか?

一度にたくさんお尋ねいただき、誠にありがとうございます。

(これも同様の質問ですが、私が探していたものには完全には答えられませんでした。 長命のJMSセッション。JMS接続の維持/ JMSセッションは常に悪い条件を開いていますか?

42
Russell

一部のメッセージが重複したり失われたりしても問題ありませんか? JMSクライアントがネットワークを介してJMSブローカーに接続する場合、API呼び出しには3つのフェーズがあります。

  1. メッセージデータを含むAPI呼び出しは、ネットワーク経由でブローカーに送信されます。
  2. API呼び出しはブローカーによって実行されます。
  3. 結果コードとすべてのメッセージデータがクライアントに送信されます。

ちょっとプロデューサーを考えてみましょう。最初のステップで接続が切断された場合、ブローカーはメッセージを取得できなかったため、アプリはメッセージを再度送信する必要があります。 3番目のステップで接続が切断された場合、メッセージは正常に送信されており、再度送信するとメッセージが重複します。アプリはこれらの違いを区別できないため、エラー時にメッセージを再送信することが安全な唯一の選択です。セッションが処理されると、メッセージはすべてのケースで安全に再送信できます。元のメッセージがブローカーに到達した場合、メッセージはロールバックされるためです。

消費者を考慮してください。 3番目のステップで接続が失われた場合、メッセージはキューから削除されますが、クライアントに戻されることはありません。ただし、セッションが処理されると、アプリケーションが再接続したときにメッセージが再配信されます。

トランザクション以外では、メッセージが失われたり重複したりする可能性があります。トランザクションの内部にはあいまいさの同じウィンドウが存在しますが、PUTまたはGETではなくCOMMIT呼び出し上にあります。トランザクションセッションでは、メッセージを2回送信または受信できますが、1つを失うことはありません。

JMS仕様はこのあいまいさのウィンドウを認識し、次のガイダンスを提供します。

クライアントがセッションでの作業をコミットしてからcommitメソッドが戻るまでの間に障害が発生した場合、クライアントはトランザクションがコミットされたかロールバックされたかを判別できません。 PERSISTENTメッセージの非トランザクション送信と送信メソッドからの戻りの間に障害が発生した場合も、同じあいまいさが存在します。

このあいまいさを処理するのはJMSアプリケーション次第です。これにより、クライアントが機能的に重複したメッセージを生成する場合があります。

セッションの回復が原因で再配信されたメッセージは、重複メッセージとは見なされません。

JMSセッションは、メッセージを失うことが本当に問題ない場合を除いて、常に処理する必要があります。セッションがトランザクション処理される場合、JMSスレッドモデルにより、スレッドごとのセッションと接続が必要になります。

パフォーマンスへの影響に関するアドバイスはベンダー固有ですが、一般に、同期点外の永続メッセージは、API呼び出しが戻る前にディスクに固定されます。しかし、トランザクション呼び出しは、永続メッセージがディスクに書き込まれる前に戻る可能性がありますCOMMITが戻る前にメッセージが永続化されている限り。ベンダーがこれに基づいて最適化する場合、いくつかのメッセージをディスクに書き込んでから、それらをバッチでコミットする方がはるかにパフォーマンスが高くなります。これにより、ブローカーはメッセージごとではなくディスクブロックごとに書き込みとディスクフラッシュを最適化できます。トランザクションに入れるメッセージの数は、メッセージのサイズとともに減少し、特定のメッセージサイズを超えると、1に減少します。

20kメッセージが比較的小さい場合(mbではなくkで測定)、スレッドごとにトランザクションセッションを使用し、コミット間隔を調整する必要があります。

28
T.Rob

ほとんどのシナリオでは、スレッドごとに1つのセッションを使用して、1つの接続と複数のセッションで作業することで十分です。一部の環境では、複数の接続を使用することで追加のパフォーマンスを得ることができます。

一部のメッセージングシステムはクラスターモードをサポートしており、接続はさまざまなノードに負荷分散されます。複数の接続を使用すると、このシナリオで複数のノードのパフォーマンスを使用できます。 (もちろん、ボトルネックがメッセージブローカー側にある場合にのみ役立ちます)。

最善の解決策は、接続のプールであり、特定の領域での動作を構成するためのオプションを管理者に提供することです。

9
roundrobin
I was wondering if having one connection, one session, and 10 producers
is the recommended way to go or not? 

確かですが、ここで注意すべき点は、シングルスレッド(つまり、Sessionオブジェクトの作成中に作成したスレッド)のみを使用していることです。 10個のプロデューサーすべてがこのセッションオブジェクトにバインドされているため、同じスレッドにバインドされています。

How about if I had one producer shared by all the threads? Would my messages
be corrupt or would it be sent out synchronized (giving no performance gain)?

私が言う非常に悪い考え。 JMS仕様では、セッションを複数のスレッドで共有してはならないことが明確に規定されています。スレッドセーフではありません。

What's the general guideline of deciding whether to create a new connection
or session if I'm always connecting to the same queue?

システムがマルチスレッドをサポートしている場合は、単一の接続から複数のセッション(各セッションは単一のスレッドに対応)を作成できます。各セッションは複数のプロデューサー/コンシューマーを持つことができますが、これらすべてをスレッド間で共有してはなりません。

4
Aniket Thakur

私がこのトピックを調査したところ、1つのセッションは1つのスレッドを意味します。これはJMS仕様に基づいています。複数のスレッド(複数のプロデューサー/コンシューマー)が必要な場合は、複数のセッションを作成する必要があります。1つの接続で問題ありません。

4
Cystal

理論的には、接続はスレッドセーフですが、その他はすべてスレッドセーフではないため、スレッドごとに1つのセッションを作成する必要があります。

実際には、使用しているJMS実装によって異なります。

1
Claude Vedovini