メッセージを生成し、JMSキューを介してその固有のコンシューマーに送信するJMSクライアントがあります。
私が欲しいのは、それらのメッセージを受け取る複数の消費者です。最初に頭に浮かぶのは、キューをトピックに変換することです。そのため、現在のユーザーと新しいユーザーがサブスクライブして、同じメッセージをすべてのユーザーに配信できます。
これには明らかに、プロデューサー側とコンシューマー側の両方で現在のクライアントコードを変更する必要があります。
また、既存のコンシューマーを変更する必要がないように、2番目のキューの作成など、他のオプションも確認したいと思います。このアプローチには、1つではなく2つの異なるキュー間で負荷を分散する(間違っている場合は修正する)などの利点があると思います。これは、パフォーマンスにプラスの影響を与える可能性があります。
私はこれらのオプションとあなたが見るかもしれない短所/長所について助言を得たいと思います。どんなフィードバックでも大歓迎です。
あなたが述べたようにあなたはいくつかのオプションがあります。
同じ効果を得るためにトピックに変換する場合、コンシューマーを永続的なコンシューマーにする必要があります。キューが提供するものの1つは、コンシューマーが生きていない場合の持続性です。これは、使用しているMQシステムによって異なります。
キューを使い続ける場合は、各コンシューマ用のキューと、元のキューをリッスンするディスパッチャを作成します。
Producer -> Queue_Original <- Dispatcher -> Queue_Consumer_1 <- Consumer_1
-> Queue_Consumer_2 <- Consumer_2
-> Queue_Consumer_3 <- Consumer_3
トピックの長所
トピックの短所
キューの長所
キューの短所
メッセージングシステムを開発するときは、トピックの方が最も強力ですが、すでにキューを使用しているので、システムの動作を変更してトピックを実装する必要があります。
複数のコンシューマを持つキューシステムの設計と実装
Producer -> Queue_Original <- Dispatcher -> Queue_Consumer_1 <- Consumer_1
-> Queue_Consumer_2 <- Consumer_2
-> Queue_Consumer_3 <- Consumer_3
ソース
問題の例外処理、接続への再接続、接続が失われた場合のキューなど、注意する必要のある他の事項があることを覚えておいてください。説明。
実際のシステムでは、最初の例外ではおそらく終了しません。システムができる限り最善の動作を続け、エラーをログに記録できるようにします。このコードでは、単一のコンシューマキューへのメッセージの送信が失敗した場合、ディスパッチャ全体が停止します。
Dispatcher.Java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package stackoverflow_4615895;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSession;
import javax.jms.Session;
public class Dispatcher {
private static long QUEUE_WAIT_TIME = 1000;
private boolean mStop = false;
private QueueConnectionFactory mFactory;
private String mSourceQueueName;
private String[] mConsumerQueueNames;
/**
* Create a dispatcher
* @param factory
* The QueueConnectionFactory in which new connections, session, and consumers
* will be created. This is needed to ensure the connection is associated
* with the correct thread.
* @param source
*
* @param consumerQueues
*/
public Dispatcher(
QueueConnectionFactory factory,
String sourceQueue,
String[] consumerQueues) {
mFactory = factory;
mSourceQueueName = sourceQueue;
mConsumerQueueNames = consumerQueues;
}
public void start() {
Thread thread = new Thread(new Runnable() {
public void run() {
Dispatcher.this.run();
}
});
thread.setName("Queue Dispatcher");
thread.start();
}
public void stop() {
mStop = true;
}
private void run() {
QueueConnection connection = null;
MessageProducer producer = null;
MessageConsumer consumer = null;
QueueSession session = null;
try {
// Setup connection and queues for receiving the messages
connection = mFactory.createQueueConnection();
session = connection.createQueueSession(false, Session.DUPS_OK_ACKNOWLEDGE);
Queue sourceQueue = session.createQueue(mSourceQueueName);
consumer = session.createConsumer(sourceQueue);
// Create a null producer allowing us to send messages
// to any queue.
producer = session.createProducer(null);
// Create the destination queues based on the consumer names we
// were given.
Queue[] destinationQueues = new Queue[mConsumerQueueNames.length];
for (int index = 0; index < mConsumerQueueNames.length; ++index) {
destinationQueues[index] = session.createQueue(mConsumerQueueNames[index]);
}
connection.start();
while (!mStop) {
// Only wait QUEUE_WAIT_TIME in order to give
// the dispatcher a chance to see if it should
// quit
Message m = consumer.receive(QUEUE_WAIT_TIME);
if (m == null) {
continue;
}
// Take the message we received and put
// it in each of the consumers destination
// queues for them to process
for (Queue q : destinationQueues) {
producer.send(q, m);
}
}
} catch (JMSException ex) {
// Do wonderful things here
} finally {
if (producer != null) {
try {
producer.close();
} catch (JMSException ex) {
}
}
if (consumer != null) {
try {
consumer.close();
} catch (JMSException ex) {
}
}
if (session != null) {
try {
session.close();
} catch (JMSException ex) {
}
}
if (connection != null) {
try {
connection.close();
} catch (JMSException ex) {
}
}
}
}
}
Main.Java
QueueConnectionFactory factory = ...;
Dispatcher dispatcher =
new Dispatcher(
factory,
"Queue_Original",
new String[]{
"Consumer_Queue_1",
"Consumer_Queue_2",
"Consumer_Queue_3"});
dispatcher.start();
コードを変更する必要はありません。それはあなたがそれを書いた方法に依存します。
たとえば、コードがMessageProducer
ではなくQueueSender
を使用してメッセージを送信する場合、キューだけでなくトピックでも機能します。同様に、MessageConsumer
ではなくQueueReceiver
を使用した場合。
基本的に、JMSアプリケーションでは、MessageProducer
、MessageConsumer
、Destination
などの非特定のインターフェイスを使用してJMSシステムとやり取りすることをお勧めします。場合、それは構成の「単なる」問題です。