gpt4 book ai didi

java - JMS 2.0-MQ 9-主题共享订阅不起作用

转载 作者:行者123 更新时间:2023-11-30 01:55:30 25 4
gpt4 key购买 nike

开发订阅MQ主题(MQ版本9)的应用程序时遇到问题。

我需要进行共享主题连接,因为该应用程序将在多个实例(群集)中运行。

规格和文档说:
“客户端使用非持久共享订阅,该客户端需要能够在多个使用者之间共享从主题订阅接收消息的工作。因此,非持久共享订阅可能具有多个使用者。来自客户端的每条消息订阅将仅传递给该订阅的其中一位消费者。”

对我来说,所有使用相同订阅名称的客户端都在同一“群集”中,一次只有一个客户端会收到一条消息。

在受此article启发的代码中,第二个客户端尝试创建共享订阅时出现了异常。我真的不明白这是否是MQ客户端库实现或代码中的错误。

这是我的示例代码:

    import javax.jms.Connection;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.Topic;

import com.ibm.mq.jms.MQTopicConnectionFactory;
import com.ibm.msg.client.wmq.WMQConstants;

public class TestGB2 {

public static void main(final String[] args) throws Exception {

for (int i = 0; i < 10; i++) {
new Thread(new MyThread("THREAD" + i, "TESTSUB/#", "myClient", "SUBTEST")).start();
}

}

public static class MyThread implements Runnable {

private final String topicString;
private final String clientId;
private final String subscriptionName;

public MyThread(final String threadName, final String topicString, final String clientId, final String subscriptionName) {
Thread.currentThread().setName(threadName);
this.topicString = topicString;
this.clientId = clientId;
this.subscriptionName = subscriptionName;
}

@Override
public void run() {

try {
System.out.println(String.format("%s : Connecting...", Thread.currentThread().getName()));
MQTopicConnectionFactory cf = new MQTopicConnectionFactory();
cf.setHostName("xxxx");
cf.setPort(1416);
cf.setQueueManager("xxxx");
cf.setTransportType(WMQConstants.WMQ_CM_CLIENT);
cf.setChannel("xxx");
cf.setClientID(clientId);

Connection con = cf.createConnection();

Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
con.start();
Topic topic = session.createTopic(topicString);
MessageConsumer messageConsumer = session.createSharedConsumer(topic, subscriptionName); // fail here

System.out.println(String.format("%s : Waiting for a message...", Thread.currentThread().getName()));
Message msg = messageConsumer.receive();
System.out.println(String.format("%s : Received :\n%s", Thread.currentThread().getName(), msg));

}
catch (Exception ex) {
System.out.println(String.format("%s : FAILED", Thread.currentThread().getName()));
ex.printStackTrace();
}

}

}
}


下面的代码尝试创建10个消耗同一主题消息的线程。只有第一个线程能够连接,其他所有线程都失败,但以下异常:

    com.ibm.msg.client.jms.DetailedIllegalStateException: JMSWMQ0026: Failed to subscribe to topic 'TESTSUB' with selector 'none' using MQSUB.
There may have been a problem creating the subscription due to it being used by another message consumer.
Make sure any message consumers using this subscription are closed before trying to create a new subscription under the same name. Please see the linked exception for more information.
at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:472)
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:214)
at com.ibm.msg.client.wmq.internal.WMQMessageConsumer.checkJmqiCallSuccess(WMQMessageConsumer.java:212)
at com.ibm.msg.client.wmq.internal.WMQMessageConsumer.checkJmqiCallSuccess(WMQMessageConsumer.java:112)
at com.ibm.msg.client.wmq.internal.WMQConsumerShadow.initialize(WMQConsumerShadow.java:1038)
at com.ibm.msg.client.wmq.internal.WMQSyncConsumerShadow.initialize(WMQSyncConsumerShadow.java:134)
at com.ibm.msg.client.wmq.internal.WMQMessageConsumer.<init>(WMQMessageConsumer.java:470)
at com.ibm.msg.client.wmq.internal.WMQSession.createSharedConsumer(WMQSession.java:938)
at com.ibm.msg.client.jms.internal.JmsSessionImpl.createSharedConsumer(JmsSessionImpl.java:4228)
at com.ibm.msg.client.jms.internal.JmsSessionImpl.createSharedConsumer(JmsSessionImpl.java:4125)
at com.ibm.mq.jms.MQSession.createSharedConsumer(MQSession.java:1319)
at TestGB.lambda$0(TestGB.java:33)
at java.lang.Thread.run(Thread.java:748)
Caused by: com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2042' ('MQRC_OBJECT_IN_USE').
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:202)
... 11 more


尝试了最后一个库:

<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>com.ibm.mq.allclient</artifactId>
<version>9.1.1.0</version>
</dependency>

最佳答案

问题摘要

问题与您的程序无关,问题与与您订阅的主题相关的模型队列有关。

在队列管理器上,如果您查看您的订阅将匹配的主题对象,则它将具有指向模型队列的参数MNDURMDL

如果查看模型队列,您会注意到两个参数,其中一个或两个都可能导致您收到错误:

[ DEFSOPT( EXCL | SHARED ) ]
[ SHARE | NOSHARE ]


这些必须设置为 DEFSOPT(SHARED)SHARE。如果将一个设置为另一个值,则共享订阅中只能有一个订阅者。



问题原因的其他详细信息

使用IBM MQ Pub / Sub,当您创建JMS订阅时,MQ会将其视为托管订阅,IBM MQ将在后台创建一个临时队列来订阅主题字符串。如果它是非持久预订,则该队列是临时动态队列。

失败的原因是,第一个线程将以独占模式打开临时动态队列,然后其他任何线程都无法打开临时动态队列,并且您收到 MQRC_OBJECT_IN_USE错误。



创建特定于应用程序的 MNDURMDL模型队列的可能原因

我怀疑这是因为IBM附带了一些不同的缺省模型队列。

非持久订户的默认设置具有以下设置:

   QUEUE(SYSTEM.NDURABLE.MODEL.QUEUE)      TYPE(QMODEL)
DEFSOPT(SHARED) SHARE


还有另一个不是特定于发布/订阅的默认队列,它们具有以下设置:

   QUEUE(SYSTEM.DEFAULT.MODEL.QUEUE)       TYPE(QMODEL)
DEFSOPT(EXCL) NOSHARE


创建供主题对象使用的模型队列很可能是使用类似以下命令的命令创建的,该命令将默认使用 SYSTEM.DEFAULT.MODEL.QUEUE的设置:

DEFINE QMODEL(xxx)


将来,您可以专门设置这两个参数,或者使用 LIKE关键字定义它,以强制它使用不同的队列来建模设置,这两个命令都在下面:

DEFINE QMODEL(xxx) DEFSOPT(SHARED) SHARE
DEFINE QMODEL(xxx) LIKE(SYSTEM.NDURABLE.MODEL.QUEUE)




有关创建和使用特定于应用程序的TOPIC对象和MODEL队列的其他详细信息

默认情况下,树的根节点由名为 SYSTEM.BASE.TOPIC的标准TOPIC对象表示,与该TOPIC相关的默认模型队列如下所示:

   TOPIC(SYSTEM.BASE.TOPIC)                TYPE(LOCAL)
TOPICSTR() MDURMDL(SYSTEM.DURABLE.MODEL.QUEUE)
MNDURMDL(SYSTEM.NDURABLE.MODEL.QUEUE)



如果您没有定义任何其他管理TOPIC对象,则所有主题均与 SYSTEM.BASE.TOPIC匹配。另外,如果您不定义任何其他管理TOPIC对象,并且想要向主题树的特定子集(例如,以 TESTSUB开头的主题字符串)授予应用程序权限,则必须通过 SYSTEM.BASE.TOPIC授予权限, turn授予应用程序访问任何不受限制的任意主题字符串的权限。

最佳实践是使用主题字符串创建一个TOPIC对象,该主题字符串与应用程序应该访问的主题树部分匹配。特定于您的 TESTSUB/#示例,如果您的管理员定义了一个新的TOPIC对象并指定了 TOPICSTR(TESTSUB),则默认值将如下创建:

   TOPIC(TESTSUB.TOPIC)                    TYPE(LOCAL)
TOPICSTR(TESTSUB) MDURMDL( )
MNDURMDL( )


空白的 MDURMDLMNDURMDL值告诉MQ使用树中下一个最接近的高级主题对象的值,如果没有其他定义,则为 SYSTEM.BASE.TOPIC,并且模型队列仍默认使用< cc>和 SYSTEM.DURABLE.MODEL.QUEUE模型队列。

管理员可以改为创建TOPIC对象并指定不同的模型队列,例如:

   TOPIC(TESTSUB.TOPIC)                    TYPE(LOCAL)
TOPICSTR(TESTSUB) MDURMDL(TESTSUB.DURABLE.MODEL.QUEUE)
MNDURMDL(TESTSUB.NDURABLE.MODEL.QUEUE)


通过这样做,他们可以定义具有共享订阅所需设置的特定于应用程序的模型队列,而不会影响SYSTEM模型队列。另一个好处是,它们可以仅对以 SYSTEM.NDURABLE.MODEL.QUEUE开头的主题字符串(例如 TESTSUBTESTSUB/ATESTSUB/B)提供应用程序权限。

关于java - JMS 2.0-MQ 9-主题共享订阅不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54669742/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com