bigywater.tech
Java · 423

JMS ACK 模式:消息何时算被确认

JMS 消息“什么时候算被确认”决定了消息会不会丢、会不会重复。这篇用进程内的 Artemis broker,把四种确认方式、监听器异常、事务回滚和死信队列的行为逐个跑出来。

m1 丢失
AUTO_ACKNOWLEDGE 下消费者取到消息后崩溃,另一个消费者再也取不到 m1;CLIENT_ACKNOWLEDGE 下 m1 以 JMSRedelivered = true 重新投递
m1、m2、m3 全部
CLIENT_ACKNOWLEDGE 下只对 m2 调用 acknowledge() 之后被确认的消息
3 次
最大投递次数设为 3 时,反复 rollback 的消息被投递的次数,之后进入死信队列 DLQ

崩溃与确认模式

实测 · 本机执行输出
  AUTO_ACKNOWLEDGE:消费者 A 取到 m1(JMSRedelivered=false,JMSXDeliveryCount=1),还没来得及处理就崩溃(直接关闭连接)
      之后消费者 B 能取到:[m2(JMSRedelivered=false,JMSXDeliveryCount=1), m3(JMSRedelivered=false,JMSXDeliveryCount=1)]
  CLIENT_ACKNOWLEDGE:消费者 A 取到 m1(JMSRedelivered=false,JMSXDeliveryCount=1),还没来得及处理就崩溃(直接关闭连接)
      之后消费者 B 能取到:[m1(JMSRedelivered=true,JMSXDeliveryCount=2), m2(JMSRedelivered=false,JMSXDeliveryCount=1), m3(JMSRedelivered=false,JMSXDeliveryCount=1)]

acknowledge() 的范围

实测 · 本机执行输出
  消费者 A 收到 m1、m2、m3,只对第 2 条 m2 调用 acknowledge()
      之后消费者 B 能取到:[m4(JMSRedelivered=false,JMSXDeliveryCount=1), m5(JMSRedelivered=false,JMSXDeliveryCount=1)](m1、m3 没有被确认过,也不会再来)

监听器异常

实测 · 本机执行输出
  监听器前两次抛出 RuntimeException,第三次成功:收到的投递依次是 [m1(JMSRedelivered=false,JMSXDeliveryCount=1), m1(JMSRedelivered=true,JMSXDeliveryCount=2), m1(JMSRedelivered=true,JMSXDeliveryCount=3)]

事务会话

实测 · 本机执行输出
  第 1 次 receive:m1(JMSRedelivered=false,JMSXDeliveryCount=1)
  rollback 之后立刻 receive:m1(JMSRedelivered=true,JMSXDeliveryCount=2)
  再 rollback 之后 receive:m1(JMSRedelivered=true,JMSXDeliveryCount=3)
  commit 之后队列里剩余:[]
  生产者事务里发送了 2 条但还没 commit:另一个消费者 500 ms 内能取到 []
  commit 之后:[tx1(JMSRedelivered=false,JMSXDeliveryCount=1), tx2(JMSRedelivered=false,JMSXDeliveryCount=1)]
  再发送 tx3 并 rollback:队列里 []

死信队列

实测 · 本机执行输出
  每次 receive 后都 rollback:共被投递 3 次:[m1(JMSRedelivered=false,JMSXDeliveryCount=1), m1(JMSRedelivered=true,JMSXDeliveryCount=2), m1(JMSRedelivered=true,JMSXDeliveryCount=3)];之后 receive 返回 null
  原队列 q5 里剩余:[]
  死信队列 DLQ 里的消息:[m1(JMSRedelivered=false,JMSXDeliveryCount=1),_AMQ_ORIG_QUEUE=q5]

分步演示

JMS ACK 模式
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。Jakarta Messaging 3.1、ActiveMQ Artemis 2.37.0(artemis-jakarta-server / artemis-jakarta-client,嵌入式、非持久化、进程内 vm://0);最大投递次数 3、重新投递延迟 0
    • 没有验证:DUPS_OK_ACKNOWLEDGE 的批量确认、持久化消息在 broker 崩溃后的重放、ActiveMQ Classic / RabbitMQ / Kafka 的对应语义、Spring 的 DefaultMessageListenerContainer 与 @JmsListener 的确认、XA 事务、重新投递延迟与退避、消息顺序与并发消费者
    京ICP备2026067502号-1京公网安备11010502063487号