【问题标题】:How to create durable subscription to ibm mq amqp topic from java program?如何从 java 程序创建对 ibm mq amqp 主题的持久订阅?
【发布时间】:2021-01-26 15:02:46
【问题描述】:

我们通过提供clientId 和订阅者名称以编程方式使用createDurableSubscriber 创建了IBM MQ AMQP TOPIC 订阅者。

我们启动程序,使其订阅 TOPIC 并停止程序。然后将消息发送到主题并再次启动接收程序,但我们无法接收发送的消息并且丢失了在持久订阅的情况下不应该发生的消息..

当订阅者使用 mqsc 命令DISPLAY TOPICDISPLAY TPSTATUSDISPLAY TPSTATUS SUBDISPLAY SUB SUBID 连接时,我们可以看到 amqp 主题及其持久订阅,但在订阅者程序停止时看不到。我们已经定义了属性DEFPSIST(YES) 并且客户端(生产者到主题)正在发送持久消息。

由于我们在订阅者的持久队列中看不到消息,消息去了哪里?是否取决于到期属性?

连接时为我们的订阅者输出DISPLAY SUB SUBID

AMQ8096: WebSphere MQ subscription inquired.


SUBID("hex sub id")
   SUB(:private:CLINET01:TOPIC01)            TOPICSTR(TOPIC01)
   TOPICOBJ(SYSTEM.BASE.TOPIC)             DISTYPE(RESOLVED)
   DEST(SYSTEM.MANAGED.DURABLE.5F6B5C2524FB9AED)
   DESTQMGR(qm.name)                   PUBAPPID( )
   SELECTOR( )                             SELTYPE(NONE)
   USERDATA(010)
   PUBACCT(***************************************************)
   DESTCORL(***************************************************)
   DESTCLAS(MANAGED)                       DURABLE(YES)
   EXPIRY(0)                               PSPROP(MSGPROP)
   PUBPRTY(ASPUB)                          REQONLY(NO)
   SUBSCOPE(ALL)                           SUBLEVEL(1)
   SUBTYPE(API)                            VARUSER(FIXED)
   WSCHEMA(TOPIC)                          SUBUSER(mqm)
   CRDATE(2020-09-28)                      CRTIME(04:14:09)
   ALTDATE(2020-09-28)                     ALTTIME(04:14:09)

订阅者 ID 具有私有(不知道为什么)和客户端 ID,但没有订阅者名称,即 sub4

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Topic;
import javax.jms.Queue;

import javax.jms.Session;
import javax.jms.TextMessage;
import java.lang.String;
import javax.jms.Destination;
import javax.naming.Context;
import org.apache.qpid.jms.JmsConnectionFactory;
import javax.jms.DeliveryMode;
import javax.naming.InitialContext;
import javax.jms.Message;

public class AMQPQueueExample1 implements Runnable  {
private static final int DELIVERY_MODE = DeliveryMode.PERSISTENT;

public void run(){
try{
 Connection connection = null;
 Context context = new InitialContext();
 ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup("myFactoryLookup");
 connection = connectionFactory.createConnection();
 connection.setClientID("123");//("WHATS_MY_PURPOSE3"); // Why do we need clientID while publishing the TOPIC from consumer / publisher
 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
 Topic priceTopic = (Topic) context.lookup("myTopicLookup1");
 MessageConsumer subscriber1 = session.createDurableSubscriber(priceTopic,"sub420"); //"sub3");
System.out.println("TOPIC "+priceTopic);

connection.start();
while(true){
TextMessage   message1 = (TextMessage) subscriber1.receive(1000);
if(message1!=null)
           System.out.println("Subscriber 1 received : " + message1.getText());


}
}catch(Exception e){
e.printStackTrace();
}
}

 public static void main(String[] args)  {

AMQPQueueExample1 amp=new AMQPQueueExample1();
 Thread thread = new Thread(amp);
thread.start();


 }
}

值取自上下文工厂和提供程序 url 的 jndi.properties 文件。

【问题讨论】:

  • 如果可以看到订阅,并且在程序运行时被视为 DURABLE(YES),但在程序停止时不存在,这表明程序正常结束并关闭删除订阅。你没有展示你的代码是什么样子的,所以没有它就不能进一步评论。看看你的订阅者程序在关闭时做了什么——它是否删除了持久订阅?如果是这样,您所描述的正是预期会发生的情况。
  • 感谢您的快速回复...这正是我检查的内容,因为程序是由其他人编写的...而且正如我所看到的..我们基本上不会在程序中取消订阅持久订阅者我们没有删除订阅...我已编辑问题以显示 runmqsc 命令的响应 DISPLAY SUB SUBID(id)
  • IBM MQ 4 位版本为 8.0.0.5
  • @MoragHughson 我们的到期时间为 0 ...应该是 UNLIMITED 以及如何在创建订阅之后或创建订阅时将其更改为 UNLIMITED
  • @JoshMc 我们的 EXPIRY 是 0 ...应该是 UNLIMITED 以及如何在创建订阅之后或创建订阅时将其更改为 UNLIMITED

标签: java ibm-mq publish-subscribe amqp jms-topic


【解决方案1】:

Matthew Whitehead "MQ Light messaging from Microsoft®.NET™ (Part 4)" 的一篇文章指出:

AMQP 通道不支持为 MQ Light 订阅设置无限到期时间。虽然可以创建具有很长生命周期的订阅,但不可能创建永久存在的订阅。

如果您希望创建永不过期的订阅,您可以通过创建 MQ 管理订阅并让 MQ Light 客户端加入和离开订阅来实现。这也有助于确保在第一个订阅者连接之前发布到主题的任何消息都不会完全丢失。阅读my previous article,了解如何将 MQ Light 客户端加入受管理的订阅。

相关的 AMQP 字段

为了提供上述到期功能,MQ Light 使用了 AMQP 1.0 的 2 个特性:

  • 源超时
  • 来源到期政策

源超时用于指定订阅到期的时间(以秒为单位)。

源到期策略用于确定导致到期计时器开始的原因。 MQ AMQP 通道仅支持链接分离的过期策略,这意味着一旦最后一个链接与订阅分离,计时器就会启动。


我搜索并找不到有关如何在 Apache QPID 中设置源超时或源过期策略的参考,但链接的博客引用了通过管理定义的订阅设置过期。根据您问题中的信息,我认为您可以提前定义类似的内容。我没有指定EXPIRY,因为这会从SYSTEM.DEFAULT.SUB 提取EXPIRY(UNLIMITED)

DEFINE SUB(':private:CLINET01:TOPIC01') TOPICOBJ(SYSTEM.BASE.TOPIC) TOPICSTR('TOPIC01') DESTCLAS(MANAGED)

当您连接您的 AMQP 订阅者时,它将恢复此现有订阅,并将到期设置为 UNLIMITED

【讨论】:

  • 我们已经使用 runmqsc 创建了具有相同名称的订阅者,该订阅者具有无限期到期,但是一旦我们的订阅者通过程序连接..过期字段值更改为 0,并且在我们关闭断开订阅者的程序之后,它已被队列管理器删除...
  • 您在我的示例中使用相同的DESTCLASS 创建了吗?
  • 在这两种情况下,我们的 DESTCLASS 都是 MANAGED
  • 我不知道答案。我建议升级到 9.0 及更高版本,或者从 IBM 购买 v8.0 的扩展支持合同并与 IBM 开立案例。
  • 我认为我写的文章在撰写本文时是正确的,但在 MQ 9.2 中不再准确。当我们在 9.2 中添加对 Qpid JMS 持久订阅的支持时,我们更改了行为以允许 MQ 订阅无限期过期。
【解决方案2】:

从 cmets 看来,您使用的是 MQ 8.0.0.5?如果是这种情况,则该版本的 MQ 不支持 Apache Qpid JMS 客户端。我相信在那个版本中,一个非常基本的非持久订阅可能工作,但任何其他 JMS 方法都不太可能。

我怀疑正在发生的事情是来自 Qpid JMS 的 AMQP 1.0 流未被该版本的 MQ 完全理解,因此订阅的到期时间被设置为 0 而不是无限制。

MQ 9.2 添加了对更多 JMS 2.0 规范的支持 - 尽管不是每个 JMS 功能。有关此处支持的方法的更多信息:

https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.2.0/com.ibm.mq.dev.doc/q125050_.htm

创建持久订阅者和/或消费者应该如您所愿。

【讨论】:

  • 感谢您的回答...我们正在尝试的一种解决方法是让客户端无法修改订阅者...我们是否有任何这样的方法可以使使用 runmqsc 离线创建的订阅者无法被客户端程序修改所以它可能无法修改它的到期时间......?
  • 不,遗憾的是没有简单的方法可以做到这一点。 MQ 9.2 版本经过特别增强以支持这些类型的 AMQP 客户端,因此唯一可行的解​​决方案是升级到 MQ 9.2。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-28
  • 2015-08-11
  • 1970-01-01
  • 2020-01-12
  • 1970-01-01
相关资源
最近更新 更多