重试与死信队列
用途:消费失败时既不丢消息、也不让一条坏消息拖垮整条链路
重试机制
「重试机制」小节链接| 消费模式 | 失败处理 |
|---|---|
| 集群消费(并发) | 返回失败/抛异常 → 消息重新投递,重试间隔逐步增大(默认最多 16 次,达到上限后进死信) |
| 顺序消费 | 队列被锁住并重试(间隔可配),会阻塞该队列后续消息 |
| 广播消费 | 不重试(本地消费,失败只能靠日志与补偿) |
重试是“至少一次”语义的来源,因此每次重试都可能造成重复,消费方必须幂等。
死信队列(DLQ)
「死信队列(DLQ)」小节链接- 达到最大重试次数仍失败的消息进入死信 Topic(
%DLQ%<consumerGroup>),不再自动投递。 - 处理动作:监控死信数量并告警 → 人工或自动分析原因 → 修复后用“重新投递/转回原 Topic”能力恢复。
- 死信消息有保留期,不能当持久存储;重要链路要有落库的失败记录。
重试设计的三个决策
「重试设计的三个决策」小节链接- 哪些异常可重试:网络抖动、依赖超时 → 重试;参数非法、业务规则拒绝 → 不重试(直接记录并跳过或进人工队列)。区分错误类型比调重试次数更重要。
- 重试预算:无限重试会在下游故障时形成风暴。设置上限 + 退避 + 抖动,并限制并发重试数。
- 失败可见性:失败必须留下可查证据(消息 ID、业务键、异常摘要、尝试次数),否则无法定位。
毒消息(Poison Message)
「毒消息(Poison Message)」小节链接一条格式异常的消息反复失败会持续消耗资源,甚至阻塞顺序队列。对策:
- 反序列化失败直接进死信/隔离队列,不进入重试。
- 按业务键统计失败率,超阈值自动隔离该键的消息。
- 隔离队列提供“人工修复后重放”的工具化入口。
与幂等、对账的关系
「与幂等、对账的关系」小节链接重试解决“暂时失败”,幂等解决“重复”,对账解决“最终没做成”。三者缺一不可:
消费失败 → 重试(有限次)→ 死信(人工/自动修复)→ 对账(发现漏网)→ 补偿常见误区
「常见误区」小节链接| 误区 | 修正 |
|---|---|
| catch 掉异常返回成功 | 消息被确认,数据永久丢失(最常见事故之一) |
| 消费逻辑里 sleep 重试 | 占满消费线程,改为依赖 MQ 重试或异步补偿 |
| 顺序消费无限重试 | 阻塞队列,必须设上限并转死信 |
| 死信无人监控 | 死信必须进告警与工单流程 |
| 重试次数调到很大当可靠性 | 只是延后失败,风暴风险更高 |
延伸阅读
「延伸阅读」小节链接- Apache RocketMQ 官方文档:Consumer 重试与死信、消息过滤
- Chris Richardson《微服务架构设计模式》第 8 章(可靠消息传递)