IBM MQ classes for JMS 中处理有害消息

中毒报文是指接收应用程序无法处理的报文,例如,由于报文的类型出乎意料,或包含应用程序逻辑无法处理的信息。 如果应用程序无法处理报文,它就会将报文滚回原来的队列。 默认情况下, IBM® MQ classes for JMS 会反复向应用程序重新发送中毒信息,这可能导致应用程序陷入循环,不断尝试处理中毒信息并将其回滚。 为了防止这种情况发生, IBM MQ classes for JMS 可以在毒报文发送到应用程序并回滚指定次数后,将其移至回滚队列。

IBM MQ classes for JMS 可检测毒信息,并利用以下属性将其转移到其他目的地:
  • 已检测到消息的 MQMD 中 BackoutCount 字段的值。
  • 包含消息的输入队列的 IBM MQ 队列属性 BOTHRESH (回退阈值) 和 BOQNAME (回退重排队列)。
    要设置 "BOTHRESH和 "BOQNAME属性,请发出以下 MQSC 命令:
    ALTER QLOCAL(your.queue.name) BOTHRESH(threshold value) 
    BOQUEUE(your.backout.queue.name)

只要应用程序回滚消息,队列管理器就会自动递增消息的 BackoutCount 字段值。

IBM MQ classes for JMS 检测到 BackoutCount 大于零的消息时,它们会将 BackoutCount 的值与 BOTHRESH 属性的值进行比较。
  • 如果 BackoutCount 小于 BOTHRESH 属性的值,那么 IBM MQ classes for JMS 会将其交付到应用程序以进行处理。
  • 但是,如果 BackoutCount 值大于或等于 BOTHRESH 属性值,那么此消息将被视为有害消息。 在此情况下, IBM MQ classes for JMS 会将消息移至 BOQNAME 属性指定的队列。 如果无法将消息放入回退队列,那么会将其移动到队列管理器的死信队列或将其废弃,具体取决于消息的报告选项。
注:
  • 如果 BOTHRESH 属性保留其缺省值 0,那么将禁用有害消息处理操作。 这意味着所有有害消息都将被放回输入队列。
  • 要注意的另一个问题是, IBM MQ classes for JMS 首次检测到 BackoutCount 大于零的消息时,会查询队列的 BOTHRESHBOQNAME 属性。 然后,将对这些属性的值进行高速缓存,并在 IBM MQ classes for JMS 迂到 BackoutCount 大于零的消息时使用这些值。

配置系统以执行有害消息处理

IBM MQ classes for JMS 在查询 BOTHRESHBOQNAME 属性时使用的队列取决于正在执行的消息传递的样式:
  • 对于点到点消息传递,这是底层本地队列。 当 JMS 应用程序使用来自别名队列或集群队列的消息时,这很重要。
  • 对于发布/预订消息传递,会创建受管队列来保存应用程序的消息。 IBM MQ classes for JMS 查询受管队列以确定 BOTHRESHBOQNAME 属性的值。
    受管队列是根据与应用程序预订的“主题”对象所关联的模型队列创建的,并从该模型队列继承 BOTHRESHBOQNAME 属性的值。 使用的模型队列取决于接收应用程序已取得持久预订还是非持久预订。
    • 用于持久预订的模型队列由“主题”的 MDURMDL 属性来指定。 该属性的缺省值为 SYSTEM.DURABLE.MODEL.QUEUE
    • 对于非持久预订,所使用的模型队列由 MNDURMDL 属性来指定。 MNDURMDL 属性的缺省值为 SYSTEM.NDURABLE.MODEL.QUEUE
查询 BOTHRESHBOQNAME 属性时, IBM MQ classes for JMS:
  • 打开本地队列或别名队列的目标队列。
  • 查询 BOTHRESHBOQNAME 属性。
  • 关闭本地队列或别名队列的目标队列。
打开本地队列或别名队列的目标队列时使用的打开选项取决于正在使用的 IBM MQ classes for JMS 版本:
  • 对于 IBM MQ 9.1.0 Fix Pack 1 和更低版本中的 IBM MQ classes for JMSIBM MQ 9.1.1,如果本地队列或别名队列的目标队列是集群队列,那么 IBM MQ classes for JMS 将使用 MQOO_INPUT_AS_Q_DEFMQOO_INQUIREMQOO_FAIL_IF_QUIESCING 选项打开队列。 这意味着运行接收应用程序的用户必须对集群队列的本地实例具有查询和获取访问权。

    IBM MQ classes for JMS 使用打开选项 MQOO_INQUIREMQOO_FAIL_IF_QUIESCING打开所有其他类型的本地队列。 为了使 IBM MQ classes for JMS 能够查询属性值,运行接收应用程序的用户必须具有对本地队列的查询访问权。

  • IBM MQ 9.1.0 Fix Pack 2 和更高版本中使用 IBM MQ classes for JMS 时,或者对于 IBM MQ 9.1.2 和更高版本,运行接收应用程序的用户必须对本地队列具有查询访问权,而不考虑队列的类型。

要将有害消息移至回退重排队列或队列管理器的死信队列,必须授予运行应用程序 putpassall 权限的用户。

为同步应用程序处理有害消息

如果应用程序通过调用下列其中一种方法同步接收消息,那么 IBM MQ classes for JMS 将在应用程序尝试获取消息时处于活动状态的工作单元中重新排队有害消息:

  • JMSConsumer.receive()
  • JMSConsumer.receive(long timeout)
  • JMSConsumer.receiveBody(Class<T> c)
  • JMSConsumer.receiveBody(Class<T> c, long timeout)
  • JMSConsumer.receiveBodyNoWait Class<T> c)
  • JMSConsumer.receiveNoWait()
  • MessageConsumer.receive()
  • MessageConsumer.receive(long timeout)
  • MessageConsumer.receiveNoWait()
  • QueueReceiver.receive()
  • QueueReceiver.receive(long timeout)
  • QueueReceiver.receiveNoWait()
  • TopicSubscriber.receive()
  • TopicSubscriber.receive(long timeout)
  • TopicSubscriber.receiveNoWait()

这意味着如果应用程序正在使用事务性 JMS 上下文或会话,那么在落实事务之前不会落实将消息移至回退队列的操作。

如果 BOTHRESH 属性设置为零之外的值,那么还应设置 BOQNAME 属性。 如果 BOTHRESH 设置为大于零的值,并且 BOQNAME 尚未设置,那么由消息的报告选项来确定相关行为:
  • 如果消息已设置 MQRO_DISCARD_MSG 报告选项,那么将丢弃此消息。
  • 如果消息指定了报告选项 MQRO_DEAD_LETTER_Q ,那么 IBM MQ classes for JMS 会尝试将消息移至队列管理器的死信队列。
  • 如果消息未设置 MQRO_DISCARD_MSGMQRO_DEAD_LETTER_Q ,那么 IBM MQ classes for JMS 会尝试将消息放入队列管理器的死信队列中。
如果尝试将消息放入死信队列由于某种原因而失败,那么消息的情况将由接收应用程序是使用事务性还是非事务性 JMS 上下文或会话来确定:
  • 如果接收应用程序正在使用事务性 JMS 上下文或会话,并且事务已落实,那么将废弃该消息。
  • 如果接收应用程序正在使用事务性 JMS 上下文或会话,并回滚事务,那么消息将返回到输入队列。
  • 如果接收应用程序已创建非事务性 JMS 上下文或会话,那么将废弃该消息。

为异步应用程序处理有害消息

如果应用程序通过 "MessageListener,异步接收信息,则 "IBM MQ classes for JMS会重新接收中毒信息,而不会影响信息的发送。 重新排队过程在任何与传递至应用程序的实际消息相关联的工作单元外部执行。

如果 BOTHRESH 设置为大于零的值,并且 BOQNAME 尚未设置,那么由消息的报告选项来确定相关行为:
  • 如果消息已设置 MQRO_DISCARD_MSG 报告选项,那么将丢弃此消息。
  • 如果消息指定了报告选项 MQRO_DEAD_LETTER_Q ,那么 IBM MQ classes for JMS 会尝试将消息移至队列管理器的死信队列。
  • 如果消息未设置 MQRO_DISCARD_MSGMQRO_DEAD_LETTER_Q ,那么 IBM MQ classes for JMS 会尝试将消息放入队列管理器的死信队列中。

如果由于某种原因尝试将消息放入死信队列失败,那么 IBM MQ classes for JMS 会将消息返回到输入队列。

有关激活规范和 ConnectionConsumers 如何处理中毒报文的信息,请参阅从 ASF 队列中删除报文

将消息移至回退队列时发生的情况

将有害消息重新排队到回退重新排队队列时, IBM MQ classes for JMS 会向其添加 RFH2 头 (如果它还没有) ,并更新消息描述符 (MQMD) 中的某些字段。

如果有害消息包含 RFH2 头 (例如,因为它是 JMS 消息) ,那么在将消息移至回退重排队列时, IBM MQ classes for JMS 会更改 MQMD 中的以下字段:
  • BackoutCount 字段重置为零。
  • 将更新消息的 "到期" 字段以反映 JMS 应用程序接收有害消息时的剩余到期时间。
如果有害消息不包含 RFH2 头,那么 IBM MQ classes for JMS 会在回退处理过程中添加一个消息并更新 MQMD 中的以下字段:
  • BackoutCount 字段重置为零。
  • 将更新消息的 "到期" 字段以反映 JMS 应用程序接收有害消息时的剩余到期时间。
  • 消息的“格式”字段更改为 MQHRF2。
  • CCSID 字段更改为 1208。
  • “编码”字段修改为 273。

此外,来自有害消息的 CCSID 和“编码”字段将被复制到 RFH2 头的 CCSID 和“编码”字段,以确保回退重新排队队列上消息的头链接是正确的。