跳转到内容

重试与死信队列

用途:消费失败时既不丢消息、也不让一条坏消息拖垮整条链路

消费模式 失败处理
集群消费(并发) 返回失败/抛异常 → 消息重新投递,重试间隔逐步增大(默认最多 16 次,达到上限后进死信)
顺序消费 队列被锁住并重试(间隔可配),会阻塞该队列后续消息
广播消费 不重试(本地消费,失败只能靠日志与补偿)

重试是“至少一次”语义的来源,因此每次重试都可能造成重复,消费方必须幂等。

  • 达到最大重试次数仍失败的消息进入死信 Topic(%DLQ%<consumerGroup>),不再自动投递。
  • 处理动作:监控死信数量并告警 → 人工或自动分析原因 → 修复后用“重新投递/转回原 Topic”能力恢复。
  • 死信消息有保留期,不能当持久存储;重要链路要有落库的失败记录。
  1. 哪些异常可重试:网络抖动、依赖超时 → 重试;参数非法、业务规则拒绝 → 不重试(直接记录并跳过或进人工队列)。区分错误类型比调重试次数更重要。
  2. 重试预算:无限重试会在下游故障时形成风暴。设置上限 + 退避 + 抖动,并限制并发重试数。
  3. 失败可见性:失败必须留下可查证据(消息 ID、业务键、异常摘要、尝试次数),否则无法定位。

一条格式异常的消息反复失败会持续消耗资源,甚至阻塞顺序队列。对策:

  • 反序列化失败直接进死信/隔离队列,不进入重试。
  • 按业务键统计失败率,超阈值自动隔离该键的消息。
  • 隔离队列提供“人工修复后重放”的工具化入口。

重试解决“暂时失败”,幂等解决“重复”,对账解决“最终没做成”。三者缺一不可:

消费失败 → 重试(有限次)→ 死信(人工/自动修复)→ 对账(发现漏网)→ 补偿
误区 修正
catch 掉异常返回成功 消息被确认,数据永久丢失(最常见事故之一)
消费逻辑里 sleep 重试 占满消费线程,改为依赖 MQ 重试或异步补偿
顺序消费无限重试 阻塞队列,必须设上限并转死信
死信无人监控 死信必须进告警与工单流程
重试次数调到很大当可靠性 只是延后失败,风暴风险更高
  • Apache RocketMQ 官方文档:Consumer 重试与死信、消息过滤
  • Chris Richardson《微服务架构设计模式》第 8 章(可靠消息传递)