消息队列负责保存和分发消息,Worker 是运行消费代码的进程。队列不会替业务完成任务,也通常不会自动保证外部数据库“恰好写一次”。
一次异步任务的流程
1 | 用户提交订单 |
如果在业务完成前 ACK,Worker 随后崩溃会造成消息丢失;如果业务完成后、ACK 前崩溃,Broker 可能再次投递,造成重复处理。
三个 Worker 会不会都处理
取决于消费模式:
- 竞争消费:同一消费组内,一条消息交给其中一个 Worker。
- 广播或独立订阅:每个订阅者都收到一份消息。
扩容 Worker 可以提高并行度,但上限还受队列分片、数据库连接、下游限流和单任务耗时约束。
幂等不是简单查一次
使用稳定事件 ID,并在数据库建立唯一约束:
1 | CREATE TABLE consumed_messages ( |
在同一事务中记录消费和修改业务:
1 | BEGIN |
只做 SELECT 再 INSERT 仍有并发窗口,唯一索引才是最终防线。支付、发券等外部副作用还需要对方支持幂等键,或在本地维护可恢复状态机。
消息积压怎么处理
先计算生产速率与消费速率:
1 | 净积压速率 = 每秒生产数量 - 每秒消费数量 |
排查顺序:
- 单条任务是否变慢或持续失败。
- 数据库、缓存和第三方接口是否成为瓶颈。
- Worker 是否被阻塞、崩溃或频繁重启。
- 队列分片是否足以支持更多消费者。
- 扩容是否会压垮下游。
Webhook 与 MQ 的区别
Webhook 是系统之间通过 HTTP 主动通知;MQ 是通过 Broker 缓冲和分发消息。Webhook 也需要重试、签名、幂等和失败补偿,不能因为使用 HTTP 就省略可靠性设计。