死信队列要不要人工介入
两个场景,方向相反:一个系统的死信队列(消息重试耗尽后转入的队列)堆了 3000 条消息,三天没人发现,客户问「积分怎么没到账」才知道;另一个系统的值班同学凌晨两点被死信告警叫醒,爬起来对着 broker 控制台手动导出、重发,天亮一看重投的全是时段性网络抖动,重试机制本来就能消化。
结论一句话:死信队列的价值在「把消费不了的消息圈出来等人裁决」,介入本身必须有人——但不是实时盯,而是每批死信在时限内有人分类处置;既不能指望全自动重投,也不能圈出来就没人管。
按成因分三类,处置动作完全不同:
| 成因 | 典型例子 | 处置 |
|---|---|---|
| 代码缺陷 | 字段解析失败、空指针 | 修代码发版,再批量重投 |
| 长时间依赖故障 | 数据库半小时不可用,超出重试窗口 | 先恢复依赖,确认恢复后批量重投 |
| 毒消息 | 数据本身残缺,永远消费失败 | 不重投,落库存证,走数据修正 |
RocketMQ 默认重试 16 次、间隔逐级拉长到小时级,这套设计已经把短时抖动挡在了死信之外——能进死信的,多数是后两类,处置前先分类,不分类全部重投只会把毒消息再毒一遍。
三条注意:
- 告警留痕:告警只报「有死信进来了」;处置走管理页的批量操作并留操作记录——翻 broker 控制台手动导出再重发,既容易选错队列,也不会留下痕迹。
- 先修后投:重投发生在修复之后,而重投的消息会重新走一遍消费逻辑,消费者本来就该有的幂等(同一笔只执行一次的防重设计,见重复消费那一篇)在这里是最后一道闸。
- 落表存证:毒消息的存证别只存在死信队列里,它有保留期限,落一张表记下原始报文和失败原因,数据修正有据可查。
系列:深文 延迟任务:超时关单、定时提醒的三种实现 | 相关 什么时候真的需要消息队列 | 技术纵深系列索引
相关文章
多租户不是加一个 tenant_id:三种隔离模型与选型
多租户不是加个 tenant_id 就完了。共享表、独立 schema、独立库,三种模型的成本和失效方式不一样。这篇按 Spring Boot + MySQL 讲我怎么选、怎么落地,以及异步、定时任务、MQ、导出这些地方怎么漏。
部门、门店、代理商,一张 sys_dept 表撑不住这三层
需求说“要加门店”,开发在 sys_dept 上加了一列 type,两行代码当天上线。三个月后加代理商,type 多个值;半年后要求门店同时归区域运营、归总部核算,parent_id 只有一个。行政组织、经营单元、外部主体这三层的差别不在层级深浅,在于谁需要历史、谁会算钱、谁是外部人。
权限系统:RBAC 不够用的地方,数据权限怎么补
一句“销售只能看自己的客户”,里面藏着行、列、入口、失效四个判定,RBAC 一个都答不了。这篇讲数据范围怎么落成一条 SQL、@DataScope 这类拼法会在哪一层漏、成本价为什么会整整齐齐出现在导出的 Excel 里,以及为什么详情接口是行级权限最大的口子。