★ Kafka 如何保证消息顺序?分区与顺序有什么关系?

结论先行:Kafka 只保证分区内有序、不保证全局有序。端到端保序需要四件事同时成立:同一业务键的消息进入同一分区、生产端顺序发送且不乱序重试、消费端对同一分区单线程(或分区内串行)处理、位移提交时机正确。任何一个环节破坏,顺序都可能被打破。

一、为什么只保证分区内有序

  • 一个分区在 Broker 端是追加写日志,天然有序;不同分区并行存储与消费,全局顺序无法保证;
  • 生产者按 key 哈希选分区:相同 key 的消息进同一分区,例如同一订单号的所有事件;
  • 消费者组内一个分区同一时刻只分配给一个消费者,分区内按位移顺序拉取;
  • 顺序的边界:Kafka 保证的是存储顺序与拉取顺序,消费端若多线程并发处理同一分区,完成顺序仍可能乱;
  • 默认分区器:未指定 key 时按 sticky 策略随机分摊,只有指定 key 才能稳定映射到同一分区;
  • 批量发送不影响:同一分区内的批量消息仍按追加顺序落盘,key 级顺序不受 batch 影响。

二、四个保序条件

环节破坏顺序的原因对策
分区选择相同 key 落入不同分区指定 key,让分区器稳定哈希
生产发送发送失败重试导致后发先至开启幂等或限制 in-flight 为 1
消费处理多线程并发消费同一分区单线程或按 key 分桶串行处理
位移提交先提交位移后处理失败丢消息处理成功后再提交,配合幂等

三、生产端配置示例

# 保证重试不乱序:不开幂等时 in-flight 必须为 1
enable.idempotence=true
max.in.flight.requests.per.connection=5
# 开启幂等后 Kafka 用序列号校验,乱序重试会被 Broker 拒绝
retries=3

四、两个高频坑

  • 分区数只能增加不能减少,规划时要按峰值吞吐预留余量,否则扩容会改变 key 与分区的映射;
  • 重平衡期间同一分区会被新消费者重复拉取尾部消息,顺序本身不破坏,但业务要能容忍重复。

常见追问 / 记忆点

  • 追问:全局有序怎么办?答:只能牺牲吞吐把分区数设为 1,或引入全局序号在消费端重排。
  • 追问:幂等生产者和顺序有什么关系?答:幂等生产者带序列号,Broker 会拒绝乱序序列,因此重试也不会打乱顺序。
  • 追问:扩容分区会影响顺序吗?答:会,分区数变化会重新计算 key 的归属,历史分区内的相对顺序仍保留,但新消息可能进入新分区。
  • 记忆点:分区内有序是根基,key 选分区、串行消费、成功再提交,四步缺一不可。
笔记加载中…