外观
ActiveMQ Classic 可靠性
本页结论:Classic 的可靠性骨架是「persistent send 落盘确认 + commit 后删除 + Broker 端强制执行的重投策略」。重投策略由客户端经连接 URL 声明(
jms.redeliveryPolicy.*);毒消息耗尽后自动进默认共享死信 ActiveMQ.DLQ,无需任何 broker 配置。
生产端:持久与确认
默认持久、同步确认。JMS producer.send(msg) 默认 PERSISTENT,阻塞直到 Broker 确认收到(持久消息已写 KahaDB)。返回即代表单节点写入成功——这是本仓库 status=confirmed 的含义。
事务发送。事务会话内一次 commit 原子发送多条消息;与消费侧事务同属 JMS 本地事务,Broker 内原子。
定时投递。属性 AMQ_SCHEDULED_DELAY=<毫秒> 让消息延迟可见,但需要 broker 开启 schedulerSupport=true(官方文档 E1;镜像默认 conf 未开启,使用前先确认配置)。
消费端:commit 即删除与崩溃窗口
本仓库实验用 Session.SESSION_TRANSACTED 会话,处理顺序固定:
text
receive → 业务写库(sqlite 事务提交)→ session.commit()(确认并删除)崩溃窗口与其它队列型 Broker 同构:
- 业务提交前崩溃:消息未 commit,仍在队列 → 重投,业务侧靠幂等表拦截重复;
- commit 后、下一轮前崩溃:无损失;
- 业务提交后、commit 前崩溃:消息重投 → 幂等表命中
duplicate_skipped。这是「至少一次 + 幂等」的标准形态。
错误做法:AUTO_ACKNOWLEDGE 会话让客户端在回调返回时自动确认——业务失败即丢消息,生产禁用。
重投:redeliveryPolicy(客户端声明、Broker 执行)
重投策略不经 broker.xml,而是客户端经连接 URL 下发、由 Broker 端强制执行(本仓库 retry-dlq 实验实测):
text
tcp://activemq:61616?jms.redeliveryPolicy.maximumRedeliveries=2&jms.redeliveryPolicy.initialRedeliveryDelay=1000- 计数口径:
maximumRedeliveries计「重投次数」,不含首次投递——设 2 实测共投递 3 次(与 Artemismax-delivery-attempts=3对齐);官方默认值为 6(E1:Redelivery Policy)。 - 触发方式:消费者
session.rollback()(或断连、未 commit 关闭会话);initialRedeliveryDelay默认 1s,可配指数退避(默认关闭)。 - 与 Artemis 的差异在配置位置(客户端 URL vs broker.xml address-setting),「服务端强制执行」的性质相同。
死信:默认共享 ActiveMQ.DLQ
- 重投耗尽后消息自动转入默认死信队列
ActiveMQ.DLQ——无需任何 broker 配置(本仓库实测:dlq-consumer 从 ActiveMQ.DLQ 收到毒消息); ActiveMQ.DLQ是全 broker 共享的:所有队列的毒消息混在一起,告警无法区分业务线。按目的地拆分专属 DLQ 用 destinationPolicy 的individualDeadLetterStrategy(官方文档 E1:Message Redelivery and DLQ Handling);- 非持久消息默认不进 DLQ(
processNonPersistent默认关闭,耗尽/过期直接丢弃)——依赖 DLQ 兜底就必须发送 persistent 消息。
实验与观察点
activemq-classic basic(L1):persistent 确认 → 业务提交 → session.commit() → 队列深度归零,验证 commit 即删除与幂等落库。activemq-classic retry-dlq(L2):毒消息 rollback 后共投递 3 次(poisonMaxAttempt=3),耗尽进 ActiveMQ.DLQ(dlqReceived=1)。
activemq-classic / retry-dlq
bash demos/activemq-classic/retry-dlq/run.shassert.out.txt
PASS confirmed: 2 PASS okReceived: 1 PASS businessCommitted: 1 PASS business_rows: 1 PASS poisonAttempts: true PASS poisonMaxAttempt: 3 PASS dlqReceived: 1 PASS dlqIsPoison: 1 RESULT: all assertions passed
consumer.out.txt
SLF4J(W): No SLF4J providers were found. SLF4J(W): Defaulting to no-operation (NOP) logger implementation SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details. [consumer] timestamp=2026-08-20T17:03:37.001451968Z level=INFO service=order-service product=activemq-classic lab=retry-dlq destination=orders-retry consumer=consumer-1 status=subscribed [consumer] timestamp=2026-08-20T17:03:37.161612084Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ000000000000000000001 eventType=order.created schemaVersion=1 aggregateId=order-1001 traceId=00000000000000000000000000000001 correlationId=order-1001 destination=orders-retry seq=1 consumer=consumer-1 attempt=1 redelivered=false deliveryDelayMs=1232 status=received [consumer] timestamp=2026-08-20T17:03:37.173111826Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ000000000000000000001 eventType=order.created schemaVersion=1 aggregateId=order-1001 traceId=00000000000000000000000000000001 correlationId=order-1001 destination=orders-retry consumer=consumer-1 attempt=1 status=business_committed [consumer] timestamp=2026-08-20T17:03:37.182671884Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ00000000000000000000P eventType=order.created schemaVersion=1 aggregateId=order-poison traceId=0000000000000000000000000000000P correlationId=order-poison destination=orders-retry seq=2 consumer=consumer-1 attempt=1 redelivered=false deliveryDelayMs=1227 status=received [consumer] timestamp=2026-08-20T17:03:37.182799673Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ00000000000000000000P eventType=order.created schemaVersion=1 aggregateId=order-poison traceId=0000000000000000000000000000000P correlationId=order-poison destination=orders-retry consumer=consumer-1 attempt=1 status=consume_failed [consumer] timestamp=2026-08-20T17:03:38.190558913Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ00000000000000000000P eventType=order.created schemaVersion=1 aggregateId=order-poison traceId=0000000000000000000000000000000P correlationId=order-poison destination=orders-retry seq=2 consumer=consumer-1 attempt=2 redelivered=true deliveryDelayMs=2235 status=received [consumer] timestamp=2026-08-20T17:03:38.190748727Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ00000000000000000000P eventType=order.created schemaVersion=1 aggregateId=order-poison traceId=0000000000000000000000000000000P correlationId=order-poison destination=orders-retry consumer=consumer-1 attempt=2 status=consume_failed [consumer] timestamp=2026-08-20T17:03:39.195644166Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ00000000000000000000P eventType=order.created schemaVersion=1 aggregateId=order-poison traceId=0000000000000000000000000000000P correlationId=order-poison destination=orders-retry seq=2 consumer=consumer-1 attempt=3 redelivered=true deliveryDelayMs=3240 status=received [consumer] timestamp=2026-08-20T17:03:39.195835373Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ00000000000000000000P eventType=order.created schemaVersion=1 aggregateId=order-poison traceId=0000000000000000000000000000000P correlationId=order-poison destination=orders-retry consumer=consumer-1 attempt=3 status=consume_failed [consumer] timestamp=2026-08-20T17:03:39.218483126Z level=INFO service=order-service product=activemq-classic lab=retry-dlq destination=orders-retry consumer=consumer-1 received=4 poisonMaxAttempt=3 status=done
dlq-consumer.out.txt
SLF4J(W): No SLF4J providers were found. SLF4J(W): Defaulting to no-operation (NOP) logger implementation SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details. [consumer] timestamp=2026-08-20T17:03:40.863180071Z level=INFO service=order-service product=activemq-classic lab=retry-dlq destination=ActiveMQ.DLQ consumer=dlq-inspect status=subscribed [consumer] timestamp=2026-08-20T17:03:41.028535995Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ00000000000000000000P eventType=order.created schemaVersion=1 aggregateId=order-poison traceId=0000000000000000000000000000000P correlationId=order-poison destination=ActiveMQ.DLQ seq=2 consumer=dlq-inspect attempt=1 redelivered=false deliveryDelayMs=5073 status=received [consumer] timestamp=2026-08-20T17:03:41.028738584Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ00000000000000000000P eventType=order.created schemaVersion=1 aggregateId=order-poison traceId=0000000000000000000000000000000P correlationId=order-poison destination=ActiveMQ.DLQ consumer=dlq-inspect attempt=1 status=inspected [consumer] timestamp=2026-08-20T17:03:41.034928590Z level=INFO service=order-service product=activemq-classic lab=retry-dlq destination=ActiveMQ.DLQ consumer=dlq-inspect received=1 poisonMaxAttempt=1 status=done
inspect-db.out.txt
SLF4J(W): No SLF4J providers were found. SLF4J(W): Defaulting to no-operation (NOP) logger implementation SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details. [inspect] timestamp=2026-08-20T17:03:39.909341182Z level=INFO service=order-service product=activemq-classic lab=retry-dlq business_rows=1 processed_rows=1 status=snapshot
producer.out.txt
SLF4J(W): No SLF4J providers were found. SLF4J(W): Defaulting to no-operation (NOP) logger implementation SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details. [producer] timestamp=2026-08-20T17:03:35.952148325Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ000000000000000000001 eventType=order.created schemaVersion=1 aggregateId=order-1001 traceId=00000000000000000000000000000001 correlationId=order-1001 destination=orders-retry seq=1 brokerMessageId=ID:b4eafb2073b0-41463-1787245415464-1:1:1:1:1 durationMs=22 status=confirmed [producer] timestamp=2026-08-20T17:03:35.959021404Z level=INFO service=order-service product=activemq-classic lab=retry-dlq messageId=01JMQ00000000000000000000P eventType=order.created schemaVersion=1 aggregateId=order-poison traceId=0000000000000000000000000000000P correlationId=order-poison destination=orders-retry seq=2 brokerMessageId=ID:b4eafb2073b0-41463-1787245415464-1:1:1:1:2 durationMs=3 status=confirmed [producer] timestamp=2026-08-20T17:03:35.959589695Z level=INFO service=order-service product=activemq-classic lab=retry-dlq destination=orders-retry sent=2 status=done
运行:bash demos/activemq-classic/basic/run.sh、bash demos/activemq-classic/retry-dlq/run.sh。
边界
- 队列无消费位点:不存在「跳过坏消息继续」的位点操作,毒消息必须靠重试上限 + DLQ 清出。
- 重投计数随消息累计(JMSXDeliveryCount 可见当前是第几次投递)。
- AMQP/STOMP/MQTT 协议接入时,确认映射为各自的 ack/disposition,语义一致但 API 不同。