MQ 的价值是削峰、解耦和异步化,但它也会把一次同步调用变成一条更长的链路。消息发出去了,不代表业务完成了。
我的判断: 异步链路的成熟度,不看“有没有发消息”,而看失败后能不能定位、能不能重放、能不能让用户看到明确进度。
先定义消息唯一键
消息必须有业务唯一键,比如订单号、任务号、批次号、外部回调 ID。消费者用这个唯一键做幂等,避免重复投递导致重复扣款、重复创建或重复写入。
重试要区分错误类型
网络抖动、数据库死锁、第三方限流,可以重试;参数错误、状态非法、权限失败,重试再多也没用。消费者应该把可重试和不可重试错误分开。
顺序不是免费的
如果业务要求同一订单内消息有序,就要把同一业务键路由到同一分区或同一队列。全局顺序代价很高,通常不应该作为默认目标。
死信和补偿表是救命绳
重试到上限后,消息不能凭空消失。死信队列、失败任务表、人工重放入口,都是生产系统需要的恢复能力。
观测要覆盖全链路
要看生产速率、消费延迟、失败率、重试次数、死信数量和积压量。没有这些指标,MQ 出问题时只会看到“用户说没生效”。
实际场景:异步任务不是把接口丢出去就完事
在广告平台和 BI 平台里,很多操作都不适合同步完成。批量创建广告可能要调用多个媒体接口;用户标签历史版本可能要按日期批量计算;看板预计算可能要扫描一段时间窗口;错误数据告警可能要定时聚合并通知。这些任务如果放在接口里同步执行,用户等待时间长,接口超时后状态也不清楚。因此后端通常会把它们拆成“提交任务 + 异步执行 + 查询结果”的模式。
但异步化不是简单把消息发出去。第一步要定义任务记录。任务表里至少要有任务 ID、业务类型、业务参数、状态、创建人、开始时间、结束时间、失败原因和重试次数。这样即使 MQ 丢失、消费者重启、第三方接口超时,系统也能从任务表恢复,而不是只依赖消息本身。
第二步是定义消息唯一键。比如批创任务可以用 batchId 或 commitNo,标签历史版本可以用 tagId + versionDate,BI 预计算可以用 dashboardId + windowStart + windowEnd。消费者拿到消息后先查任务状态,如果已经成功,就直接跳过;如果正在处理中,就避免并发重复执行;如果失败且可重试,再进入补偿逻辑。
第三步是区分失败类型。媒体接口限流、网络超时、数据库死锁,这些可以重试;参数缺失、权限不足、配置不存在、媒体字段不合法,重试没有意义。不可重试的错误要尽快落库,让用户看到失败原因;可重试错误要有退避策略,避免短时间内把外部系统打得更不稳定。
异步链路还要考虑“部分成功”。批量创建里可能 100 个广告成功 90 个,失败 10 个;路径分析保存结果分群时可能 SQL 计算成功,但写入结果表失败;看板预计算可能某个组件失败。好的异步链路不应该只有 SUCCESS 和 FAILED 两个状态,还应该能表达 PART_SUCCESS,并提供失败项明细和重提入口。
最后是观测。MQ 的积压量只是底层指标,业务还需要看任务成功率、平均耗时、失败类型分布、重试次数和人工重提次数。否则系统出了问题,开发只能看到“消息还在消费”,却不知道用户为什么看不到结果。异步链路做得好,用户感受到的是 “任务可追踪”;做得不好,用户感受到的是 “点了没反应”。