顺序与事务
顺序和事务是 MQ 的高阶话题:顺序是业务刚需(支付流程),事务是跨分区原子性。
顺序保证:分区内有序
Kafka 的顺序边界:同一分区内有序,跨分区无序。
保证顺序 = 同 key 同分区
订单 1001 的所有消息用 key="order_1001" → 同一分区 → 严格有序| 破坏顺序的场景 | 解法 |
|---|---|
| 重试乱序 | 幂等生产者 + max.in.flight=1(或重试等待) |
| 多消费者并行 | 单分区单消费者(分区数=1 时全序) |
| 消费重试阻塞 | 顺序消费遇到失败要阻塞或特殊处理(不能跳过) |
工程要点:
- 关键业务(支付、状态机)用单分区或按业务 key 分区
- 顺序消费的吞吐牺牲:单分区 = 单消费者 = 无并行
顺序消费的失败处理
顺序场景消费失败不能简单跳过(后续消息依赖前序):
| 方案 | 机制 |
|---|---|
| 阻塞重试 | 失败重试直到成功(可能卡住) |
| 暂停分区 | 记录失败位置,重试队列补偿 |
| 状态机幂等 | 消息本身带状态,重复/乱序可自愈 |
事务:跨分区原子
事务让一批消息跨分区原子写入(要么全成功要么全失败):
生产者: initTransactions → beginTransaction → send(多个分区)
→ commitTransaction(或 abort)- 底层:事务协调器(Transaction Coordinator)+ 事务日志 + 幂等机制扩展
- 消费者侧:
isolation.level=read_committed只读已提交事务消息 - exactly-once 语义:事务 + 幂等 + 消费端幂等组合
面试话术:Kafka 事务 = 跨分区原子写 + 消费者过滤未提交。常用场景:多表变更 + 消息的一致性(本地消息表/事务消息替代方案见分布式事务篇)。
顺序 + 事务的边界
| 能力 | 范围 |
|---|---|
| 幂等 | 单分区去重 |
| 顺序 | 分区内有序 |
| 事务 | 跨分区原子 |
| 端到端 exactly-once | 事务 + 消费幂等 + 存储幂等(很难全链路) |
面试追问
- Kafka 的顺序边界? 分区内有序,跨分区无序。同 key 同分区是标准解法
- 重试会破坏顺序吗? 会:批次重试可能乱序。幂等 + max.in.flight=1 缓解
- 顺序消费失败怎么办? 不能跳过:阻塞重试或重试队列补偿。吞吐会牺牲
- 事务解决什么? 跨分区原子写(全成或全败)。消费者 read_committed 读已提交
- exactly-once 怎么做? 事务 + 幂等生产者 + 消费端幂等。全链路很难