179.14. JMS を介したリクエスト/リプライ

Camel は JMS 経由の Request Reply をサポートしています。本質的に、メッセージを JMS キューに送信する場合、Exchange の MEP は InOut である必要があります。

Camel は、パフォーマンスとクラスター化された環境に影響を与える JMS を介した要求/応答を設定するための多くのオプションを提供します。次の表は、オプションをまとめたものです。

オプションパフォーマンスCluster説明

Temporary

高速

はい

一時キューは応答キューとして使用され、Camel によって自動作成されます。これを使用するには、replyTo キュー名を指定 しないでください。オプションで、replyToType=Temporary を設定して、一時キューが使用されていることを目立たせることもできます。

共有

Slow

はい

共有永続キューが応答キューとして使用されます。キューは事前に作成する必要がありますが、Apache ActiveMQ などの一部のブローカーはオンザフライで作成できます。これを使用するには、replyTo キュー名を指定する必要があります。オプションで、replyToType=Shared を設定して、共有キューが使用されていることを目立たせることもできます。共有キューは、複数のノードがこの Camel アプリケーションを同時に実行しているクラスター環境で使用できます。すべてが同じ共有応答キューを使用しています。これが可能なのは、予期される応答メッセージを関連付けるために JMS メッセージセレクターが使用されているためです。ただし、これはパフォーマンスに影響します。JMS メッセージセレクターは低速であるため、Temporary キューや Exclusive キューほど高速ではありません。パフォーマンスを向上させるためにこれを微調整する方法については、以下を参照してください。

排他的

高速

No (*Yes)

応答キューとして専用の永続キューが使用されます。キューは事前に作成する必要がありますが、Apache ActiveMQ などの一部のブローカーはオンザフライで作成できます。これを使用するには、replyTo キュー名を指定する必要があります。また、replyToType=Exclusive を設定して Camel に排他的キューを使用するように指示する 必要 があります。replyTo キュー名が設定されている場合はデフォルトで Shared が使用されるためです。排他的応答キューを使用する場合、JMS メッセージセレクターは使用され ない ため、他のアプリケーションもこのキューを使用してはなりません。複数のノードがこの Camel アプリケーションを同時に実行しているクラスター環境では、専用キューを使用 できません。応答キューが要求メッセージを送信したのと同じノードに戻ってきた場合、制御できないためです。これが、共有キューが JMS メッセージセレクターを使用してこれを確認する理由です。ただし、各 Exclusive 応答キューをノードごとに一意の名前で設定すると、クラスター化された環境でこれを実行できます。その後、応答メッセージは、応答メッセージを待機する特定のノードのキューに送り返されます。

concurrentConsumers

高速

Camel 2.10.3: 使用中の同時メッセージリスナーを使用して、応答メッセージを同時に処理できます。範囲は、concurrentConsumers および maxConcurrentConsumers オプションを使用して指定できます。注意: Shared 応答キューを使用すると、同時リスナーではうまく機能しない可能性があるため、このオプションは注意して使用してください。

maxConcurrentConsumers

高速

Camel 2.10.3: 使用中の同時メッセージリスナーを使用して、応答メッセージを同時に処理できます。範囲は、concurrentConsumers および maxConcurrentConsumers オプションを使用して指定できます。注意: Shared 応答キューを使用すると、同時リスナーではうまく機能しない可能性があるため、このオプションは注意して使用してください。

JmsProducerInOut を検出し、使用する返信先を含む JMSReplyTo ヘッダーを提供します。デフォルトでは、Camel は一時キューを使用しますが、エンドポイントで replyTo オプションを使用して、固定応答キューを指定できます (固定応答キューについては以下を参照してください)。

Camel は応答キューをリッスンするコンシューマーを自動的にセットアップするので、何もする必要はあり ません。
このコンシューマーは、返信をリッスンする Spring DefaultMessageListenerContainer です。ただし、同時コンシューマーは 1 つに固定されています。
つまり、返信を処理するスレッドは 1 つしかないため、返信は順番に処理されます。返信をより速く処理したい場合は、同時実行を使用する必要があります。ただし、concurrentConsumer オプションは使用 しません。以下のルートに示すように、代わりに Camel DSL の threads を使用する必要があります。

Camel 2.10.3 以降を使用している場合は、スレッドを使用する代わりに、concurrentConsumers オプションを使用します。以下を参照してください。

from(xxx)
.inOut().to("activemq:queue:foo")
.threads(5)
.to(yyy)
.to(zzz);

このルートでは、5 つのスレッドを持つスレッドプールを使用して応答を非同期にルーティングするように Camel に指示します。

Camel 2.10.3 以降では、concurrentConsumers および maxConcurrentConsumers オプションを使用して、同時スレッドを使用するようにリスナーを設定できるようになりました。これにより、以下に示すように Camel でこれを簡単に設定できます。

from(xxx)
.inOut().to("activemq:queue:foo?concurrentConsumers=5")
.to(yyy)
.to(zzz);

179.14.1. JMS を介したリクエスト/リプライと共有固定リプライキューの使用

以下の例に示すように、JMS を介して Request Reply を実行するときに固定のリプライキューを使用する場合は、注意してください。

from(xxx)
.inOut().to("activemq:queue:foo?replyTo=bar")
.to(yyy)

この例では、bar という名前の固定応答キューが使用されています。デフォルトでは、Camel は、固定応答キューを使用する場合にキューが共有されていると想定するため、JMSSelector を使用して、予想される応答メッセージのみをピックアップします (たとえば、JMSCorrelationID に基づいて)。排他的な固定応答キューについては、次のセクションを参照してください。つまり、一時キューほど高速ではありません。receiveTimeout オプションを使用して、Camel が応答メッセージをプルする頻度を高速化できます。デフォルトでは 1000 ミリ秒です。したがって、より高速にするために、次のように 250 ミリ秒に設定して、1 秒あたり 4 回プルすることができます。

from(xxx)
.inOut().to("activemq:queue:foo?replyTo=bar&receiveTimeout=250")
.to(yyy)

これにより、Camel がプルリクエストをメッセージブローカーにより頻繁に送信するようになり、より多くのネットワークトラフィックが必要になることに注意してください。
一般に、可能であれば一時キューを使用することをお勧めします。

179.14.2. JMS を介したリクエストとリプライ、および専用の固定リプライキューを使用

Camel 2.9 以降で利用可能

前の例では、Camel は bar という名前の固定応答キューが共有されていると予想し、JMSSelector を使用して、期待する応答メッセージのみを消費します。ただし、JMS selectos は低速であるため、これを行うには欠点があります。また、応答キューのコンシューマーは、新しい JMS セレクター ID での更新が遅くなります。実際には、receiveTimeout オプションがタイムアウトしたときにのみ更新されます。デフォルトでは 1 秒です。したがって、理論的には、応答メッセージが検出されるまでに約 1 秒かかる可能性があります。一方、固定リプライキューが Camel リプライコンシューマー専用である場合は、JMS セレクターの使用を避けることができるため、パフォーマンスが向上します。実際、一時キューを使用するのと同じくらい高速です。そのため、Camel 2.9 以降では、Exclusive に設定できる ReplyToType オプションを導入しました。
以下の例に示すように、応答キューが排他的であることを Camel に伝えます。

from(xxx)
.inOut().to("activemq:queue:foo?replyTo=bar&replyToType=Exclusive")
.to(yyy)

キューはすべてのエンドポイントに対して排他的でなければならないことに注意してください。したがって、ルートが 2 つある場合は、次の例に示すように、それぞれに一意の応答キューが必要です。

from(xxx)
.inOut().to("activemq:queue:foo?replyTo=bar&replyToType=Exclusive")
.to(yyy)

from(aaa)
.inOut().to("activemq:queue:order?replyTo=order.reply&replyToType=Exclusive")
.to(bbb)

クラスター環境で実行する場合も同様です。次に、クラスター内の各ノードは一意の応答キュー名を使用する必要があります。そうしないと、クラスター内の各ノードが、別のノードでの応答として意図されたメッセージを取得する可能性があります。クラスター化された環境では、代わりに共有応答キューを使用することをお勧めします。