异步化与消息队列
异步化的价值三连:削峰填谷、系统解耦、异步提速。面试主线:异步解决什么、MQ 怎么选、消息怎么不丢。
三个价值
削峰填谷: 峰值流量被队列吸收
| 价值 | 说明 | 例子 |
|---|---|---|
| 削峰填谷 | 峰值流量先入队,下游按能力消费 | 秒杀、抢购 |
| 解耦 | 生产者不关心消费者,增减消费者不改生产方 | 下单后通知/积分/搜索各自订阅 |
| 异步提速 | 耗时操作后台做,接口快速返回 | 发邮件、生成报表 |
Kafka vs RabbitMQ
| 维度 | Kafka | RabbitMQ |
|---|---|---|
| 模型 | 分区日志,拉模式消费 | 队列 + 交换机,推模式 |
| 吞吐 | 百万级 | 万级 |
| 顺序性 | 分区内有序 | 单队列有序 |
| 消息删除 | 按保留时间,消费后不删 | 消费确认后删除 |
| 路由 | 按 topic 分区 | 灵活路由(direct/topic/fanout) |
| 运维 | 重(ZooKeeper/KRaft) | 轻 |
| 典型场景 | 日志、大数据流、高吞吐管道 | 业务消息、任务分发、复杂路由 |
选型一句话:高吞吐、顺序、日志流用 Kafka;业务消息、灵活路由、中小规模用 RabbitMQ。
消息可靠性:不丢的三段
| 阶段 | 机制 |
|---|---|
| 生产不丢 | 生产者确认(Kafka acks=all,RabbitMQ publisher confirm) |
| 存储不丢 | 落盘持久化 + 副本(见消息队列高可用篇) |
| 消费不丢 | 消费确认 + 手动 ack(处理成功再确认),失败进重试/死信 |
关键陷阱:先确认后处理会丢(消费端挂了消息已 ack),先处理后确认会重复(处理成功但 ack 失败,重投)。所以消费端必须幂等(见重试与幂等篇)。
顺序与重复
- 顺序消息:Kafka 同一分区内有序,把需要顺序的业务 key 哈希到同一分区;RabbitMQ 单队列有序
- 重复消费:MQ 的 at-least-once 语义下重复是常态,消费端幂等(唯一键)是标准解法
- 消息积压:监控消费 lag,积压时扩容消费者(分区数要提前规划,Kafka 分区数是扩并发的上限)
面试追问
- 异步化三个价值? 削峰填谷、解耦、提速。削峰是 MQ 最经典的场景
- Kafka 和 RabbitMQ 怎么选? 高吞吐日志流用 Kafka,业务消息灵活路由用 RabbitMQ。吞吐差一个量级
- 消息怎么保证不丢? 三段:生产确认、存储副本、消费手动 ack。任何一段失误都会丢
- 重复消费怎么办? 消费端幂等:唯一键去重。MQ 是 at-least-once,重复不可避免,幂等是解
- 顺序消息怎么做? Kafka 按 key 哈希到同一分区(分区内有序);RabbitMQ 单队列。注意分区数决定并发上限