Appearance
消息队列:可靠交付与消费的设计检查
修订于 2026-10-12:原文的刷盘吞吐对比、金融系统事故和“30 分钟清空 500 万条积压”等数字没有测试记录,已删除。
消息队列能把生产者与消费者在时间和容量上解耦,也带来了新的可靠性边界。最重要的问题不是“用了哪款队列”,而是每一段链路在失败时由谁负责、如何确认、怎样恢复。
把一条消息拆成三段
- 生产者 → Broker:写入客户端套接字不等于 Broker 已接收。需要使用产品支持的发布确认或事务机制,并处理确认丢失时“结果未知”的状态。
- Broker 存储与复制:持久化、复制数量、确认时机和故障模型决定可恢复性。不能把“同步刷盘”简化成“绝对不会丢”。
- Broker → 消费者:消费者何时确认取决于业务处理是否完成。过早确认可能丢业务;处理后确认可能在确认丢失时收到重复投递。
RabbitMQ 文档区分生产者确认与消费者确认:两者各自覆盖一段链路,互相并不知晓。其他产品也有各自的交付语义与配置,不能直接套用 RabbitMQ 的接口名。
处理重复与顺序
对于可能重复投递的流程,消费者应依据稳定的消息 ID 或业务操作 ID 做幂等处理。若业务先写数据库再确认消息,数据库提交成功而确认失败时,消息可能再次到达;重复执行必须可识别。幂等记录和业务副作用应尽量在同一事务边界内完成。
顺序保证通常有范围,例如同一分区、同一队列或同一业务键。先写清楚业务到底需要全局顺序、同一用户顺序,还是只需因果关系,再检查产品支持与消费者并发策略。高并发和严格全局顺序往往存在吞吐上的取舍。
积压怎么处理
积压增长说明生产速率长期高于消费速率,或消费者被下游调用阻塞。排查时记录入队速率、出队速率、最老消息年龄、失败重试次数、死信量和下游延迟。扩容消费者前要确认是否受分区数、数据库或外部 API 限制;否则可能把压力转移到下游。
失败消息应有有限重试、退避、死信或人工处理路径。无限重试同一条消息会阻塞后续处理;直接丢弃则可能违反业务要求。恢复演练应覆盖 Broker 重启、消费者崩溃、网络中断和确认丢失。
选型前的五个问题
- 需要什么交付语义、保留期限和恢复目标?
- 需要多大吞吐、可接受多少延迟?数据量与消息大小分布是什么?
- 顺序、延迟投递、事务协作和死信处理分别有什么要求?
- 团队能否运维目标产品,监控和排错工具是否足够?
- 在真实负载与故障条件下,端到端测试结果如何?
不要把某产品固定写为“交易专用”、另一产品固定写为“日志专用”;先测需求和运维能力。