🎯为什么需要消息队列
三个经典价值:解耦、异步、削峰。一句话——让系统"不那么同步、不那么紧绑、不那么怕洪峰"。
解耦:生产者不必知道谁消费,新增消费者无需改生产者。
异步:生产者发完即返回,耗时操作后台慢慢消费。
削峰:突发流量先堆在队列,消费者按自己节奏处理,保护后端。
异步:生产者发完即返回,耗时操作后台慢慢消费。
削峰:突发流量先堆在队列,消费者按自己节奏处理,保护后端。
🧩两种核心模型
① 点对点(Queue / 竞争消费)
一条消息只被一个消费者处理。多个消费者组成"消费组",抢着消费,天然做负载均衡。典型场景:订单处理、任务分发。
② 发布/订阅(Topic / 广播)
一条消息被所有订阅者收到。典型场景:事件通知、日志广播、缓存失效。Kafka 用"消费组"把两者统一:组内竞争、组间广播。
记忆:Queue=一个活一人干;Topic=一个活所有人收到。Kafka 的 Topic + Consumer Group 同时实现了这两种语义。
🧱核心工作模式
异步处理
注册成功后,发短信、发邮件、初始化画像等非核心链路,丢进 MQ 异步做,主流程秒回。
应用解耦
下单系统只发"订单已创建"事件,库存、积分、推荐各自订阅,互不依赖、独立扩容。
流量削峰
秒杀时请求先入队,后端按数据库承载能力匀速消费,避免被打垮。
消息驱动 / 事件溯源
把状态变更作为事件流,下游可重放(如 CDC 数据同步),也可做审计与回放。
🛡️可靠性:不丢、不重、不卡
投递语义(面试必考三级):
| 语义 | 含义 | 能否做到 |
|---|---|---|
| At most once | 最多一次,可能丢 | 易,但不安全 |
| At least once | 至少一次,可能重复 | 常见(Kafka 默认),配合幂等 |
| Exactly once | 恰好一次,不丢不重 | 难,需事务/幂等+去重(Kafka 事务、Flink 两阶段) |
生产者不丢:用
Broker 不丢:副本机制 + 落盘(fsync)。
消费者不丢:先处理业务再提交 offset,避免"消费中宕机 offset 已提交"导致消息丢失。
acks=all(ISR 全收)+ 重试。Broker 不丢:副本机制 + 落盘(fsync)。
消费者不丢:先处理业务再提交 offset,避免"消费中宕机 offset 已提交"导致消息丢失。
🔁幂等:消息重复怎么办
网络重试、Rebalance、acks=all 都会造成消息被消费多次。幂等保证"处理多次 = 处理一次"。
常见幂等方案
① 唯一键 + 数据库去重表(如订单号):插入前查,存在则跳过。
② 业务状态机:已支付→不再处理支付消息。
③ Redis SETNX / 原子锁:用 messageId 占位防重。
④ Kafka 幂等生产者:broker 端按 pid+seq 去重,避免生产者重试产生重复。
口诀:"做不到 exactly-once,就做 at-least-once + 幂等"。这是工业界最务实的组合。
🔢顺序消费
很多业务要求"同一订单的消息按顺序处理"(如 创建→支付→发货)。
Kafka 的顺序保证:同一
partition 内消息有序;只要把同一业务键(如订单ID)哈希到同一 partition,且单 partition 单线程消费,即可保证全局顺序。代价:顺序消费会牺牲并行度(partition 内串行)。所以"要顺序"和"要高并发"要按业务键粒度权衡,通常只需"按订单顺序"而非"全局顺序"。
⚖️主流 MQ 选型对比
| 维度 | Kafka | RocketMQ | RabbitMQ |
|---|---|---|---|
| 定位 | 高吞吐日志/流 | 高可靠事务消息 | 低延迟路由 |
| 吞吐量 | 极高(百万级/s) | 高 | 中(万级/s) |
| 延迟 | 毫秒~秒 | 毫秒 | 微秒~毫秒 |
| 顺序 | partition 级 | queue 级 | 单队列 |
| 事务消息 | 支持(事务API) | 强(半消息机制) | 弱 |
| 典型场景 | 日志、埋点、流处理 | 电商交易、金融 | 后台任务、RPC替代 |
选型直觉:要吞吐/流处理 → Kafka;要事务/金融级可靠 → RocketMQ;要灵活路由/低延迟 → RabbitMQ。深入 Kafka 见 kafka-deep-dive。
🎯面试要点速记
三大价值:解耦、异步、削峰。
两种模型:点对点(竞争消费)+ 发布订阅(广播);Kafka 用 Topic+Group 统一。
投递语义:at-most / at-least / exactly once,业界多用 at-least-once + 幂等。
不丢消息:生产者 acks=all+重试、Broker 副本落盘、消费者先处理后提交 offset。
幂等方案:去重表 / 状态机 / Redis 原子锁 / Kafka 幂等生产者。
顺序:同 key 哈希到同 partition + 单线程消费。
必考题:"如何保证消息不丢失?"——分三段答:生产端(确认+重试)、服务端(多副本+刷盘)、消费端(先消费后提交位移)。漏掉任何一段都算不完整。