《JMS 消息重试机制与死信队列配置指南:以 IBM MQ 与 TongLinkQ 为例》
大家好,我是G探险者!
🔄 第 4 篇
📌 为什么要研究重试与死信机制?
在 JMS 消费过程中,我们总会遇到:
- 消息处理失败,能不能重试几次?
- 失败多次后,怎么避免“炸队列”?
- 失败的消息去哪了?怎么查?
- Spring 抛异常了,MQ 会自动重投吗?
- MQ 的最大重试次数、重试间隔如何设置?
这些问题的核心是:如何设置并合理使用 MQ 的 Redelivery + DLQ 机制。
✅ 一、消息重试机制原理概览
标准流程如下:
MQ 投递消息 → Listener.onMessage() → 处理失败 → 抛异常 → Spring rollback↓MQ 检测未确认 → 标记 redelivery → 重投消息(N次) → 超过最大次数 → 投递到 DLQ(死信队列)
📦 二、Spring 中的回滚行为触发 MQ 重试
public class MyListener implements MessageListener {@Overridepublic void onMessage(Message message) {try {doBusiness(message);} catch (Exception e) {// ❗ 抛异常 = rollback = MQ 重试throw new RuntimeException("处理失败", e);}}
}
前提是你配置了:
container.setSessionTransacted(true);
或者:
container.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED);
📚 三、MQ 的重试策略配置(不同厂商)
🔷 1. IBM MQ 的重投配置方式
IBM MQ 的重投行为不是在客户端配置,而是在 队列层面配置:
方法一:使用 MQSC 命令配置
DEFINE QLOCAL('MY.QUEUE') +DEFPSIST(YES) +BOTHRESH(5) +BOQNAME('MY.DEAD.QUEUE') +RETRYINT(3000)
参数 | 说明 |
---|---|
BOTHRESH | 最大重试次数 |
BOQNAME | 重试失败后的死信队列名称 |
RETRYINT | 重试间隔(毫秒) |
方法二:通过 MQ 管理控制台配置 DLQ 与重投
🔷 2. TongLinkQ 的重试配置
TongLinkQ 支持客户端配置重连、重试,但更推荐通过队列策略配置:
示例策略项:
msg.retry.count=5
msg.retry.interval=3000
msg.dlq.name=DLQ.TLQ
📌 四、Spring 层 + MQ 层协同策略
层级 | 角色 | 行为 |
---|---|---|
Spring JMS 容器 | 消费监听容器 | 抛异常 → rollback |
JMS Session | 事务上下文 | rollback 会拒绝 ack |
MQ Broker | 检测未确认消息 | 重发该消息 |
MQ Broker | 检测超重试次数 | 投递到 DLQ |
📁 五、死信队列(DLQ)管理
为什么需要 DLQ?
- 避免坏消息无限重试、拖垮系统
- 保证坏消息不丢失
- 后续可人工处理或走补偿逻辑
DLQ 消息示例(IBM MQ)
Queue = MY.DEAD.QUEUE
Payload = 原始消息
Headers:- Reason Code: MQRC_BACKED_OUT- Original Queue: MY.QUEUE- DeliveryCount: 6
🛠️ 实践建议:
- 每个业务队列都应该绑定一个 DLQ
- DLQ 中的消息应有监控 + 告警
- 建议开发“死信消费工具”:支持查询、重投、丢弃等操作
🧠 六、Spring Retry 与 MQ Retry 的区别
类型 | 控制位置 | 默认行为 | 适用范围 |
---|---|---|---|
Spring Retry | 应用层重试 | 重试不回滚事务 | 网络调用、数据库 |
MQ Redelivery | MQ Broker 层 | 重试会重新发消息 | MQ 消息处理 |
✅ MQ 消息处理建议依赖 MQ Retry + DLQ,而非 Spring Retry。
☑️ 七、实战总结
场景 | 推荐策略 |
---|---|
消息消费失败后希望自动重试 | 开启 setSessionTransacted(true) ,并抛异常 |
控制最大重试次数和间隔 | MQ 队列上配置,如 BOTHRESH 、RETRYINT |
失败后不丢弃消息 | 配置 DLQ,并开启告警通知 |
如何处理 DLQ 中的消息 | 开发 DLQ 消费工具或人工平台 |
Spring Retry 与 MQ Retry | 不建议混用,重点依赖 MQ Retry |
📘 下一篇预告:
第 5 篇:《搞懂 Spring 的 CachingConnectionFactory:为什么发送消息别直接用原始 ConnectionFactory》
本文将深入解析 JMS 的发送端连接池如何保证重连、高性能、连接复用,并分析它与监听容器的连接机制区别。