Kafka 分区设计 + 高吞吐原理

mq 📚 learning kafka-partition-performance · kafka · partition · performance · zero-copy · sendfile · page-cache · high-throughput

TL;DR(30 秒扫完)

  • 分区四大作用:并行度上限 / 分区内有序 / 横向扩展 / 容错隔离
  • 消费者数不能超过分区数:多出的消费者空转,扩容分区前得评估
  • 高吞吐 8 层机制:顺序 I/O + 零拷贝 + Page Cache + 分区并行 + 批量压缩 + 长轮询 + 索引优化 + 异步复制
  • 零拷贝:mmap + sendfile 组合,磁盘 → 内核 → 网卡,绕过用户态和 CPU 二次拷贝
  • 分区数量权衡:一般不超过 100,多了 Rebalance 频繁 + 元数据管理开销

关键结论

结论 A分区不是为了"消息均衡",而是"分区内有序 + 消费者并行"的语义基础
结论 BKafka 快不是靠某一个点,而是8 层协同(存储 + 网络 + 调度 + 副本)
结论 C零拷贝(sendfile + mmap)是消费端性能的关键——传统 read-write 4 次拷贝变 2 次
结论 DKafka 用磁盘而非内存,是因为 Page Cache 让热数据全在内存,磁盘只是兜底

完整讲解(费曼四步)

STEP 1 · 概念

Partition 是 Topic 下的并行处理单位,每个 Partition 是独立的有序日志;高吞吐是 Kafka 通过 8 层机制叠加达到的性能表现。

STEP 2 · 大白话

流水线比喻:
  • 单分区 = 单条流水线,一次只能处理一条产品
  • 多分区 = 多条并行流水线,产能翻倍
  • Kafka 的"快"不是流水线变快,而是"流水线 + 智能调度 + 快速搬运 + 批量打包"一起上

STEP 3 · 底层

分区的四大作用

作用说明关键点
并行度N 个分区 → 消费者组最多 N 个消费者并行消费者数 ≤ 分区数
顺序性Partition 内 offset 严格递增全局无序,局部有序
扩展性分区分布在不同 Broker,扩容加节点加分区num.partitions 只能增不能减
容错每个分区有副本(ISR),Leader 挂由 ISR 接管故障隔离

Partition Key 路由

partition = hash(key) % numPartitions
  • Key 一致 → 同一分区 → 保证同一业务实体顺序消费
  • Key=null → 粘性分区(sticky partitioner)

高吞吐 8 层机制

层机制收益
1. 存储顺序磁盘 I/O(append-only log)磁盘顺序写接近内存,可达 600MB/s+
2. 网络零拷贝(mmap + sendfile)磁盘 → 内核 → 网卡,2 次拷贝 vs 传统 4 次
3. 内存Page Cache热数据天然在内存,磁盘只是兜底
4. 并发分区并行多 Broker 多分区并行读写,线性扩展
5. 调度批量 + 压缩linger.ms + batch.size 攒批;lz4/zstd 压缩
6. 调度长轮询无消息时挂起连接,避免 5s 空轮询
7. 索引Hash Index + Time Index.index + .timeindex,二分查找 O(log n)
8. 副本异步复制Leader 写本地即返回,ISR 异步追

零拷贝的实现细节

传统 read-write 需要 4 次拷贝:
磁盘 → 内核缓冲 → 用户态 → 内核 socket → 网卡
Kafka 用 mmap + sendfile:
磁盘 → 内核页 → 网卡
  • mmap 让 CRC 校验在 mmap 时同步完成
  • sendfile 直接把内核页拷到网卡
  • 数据不进入用户态,CPU 和带宽开销大降

分区数量的权衡

情况表现
太少并行度不足,消费者打不满
太多Rebalance 频率上升、文件句柄爆炸、元数据管理开销
经验值单分区单消费者 QPS 到瓶颈时再加,一般 ≤ 100
关键约束:
  • num.partitions 只能增加不能减少(减少会破坏 offset→消息映射)
  • 分区扩容会改变消息路由,影响顺序性
  • 消费者数 > 分区数 → 多出的消费者空转

STEP 4 · 简化

一句话总结:分区决定"并行度 + 局部有序",高吞吐是 8 层机制协同的结果。 记忆口诀:
  • 分区:并行、有序、扩展、容错
  • 8 层:顺序写、零拷贝、页缓存、并行读、批量压、长轮询、二分查、异步复
  • 零拷贝:mmap + sendfile,2 次拷贝
  • 分区数:≤ 100,只能增不能减

常见误区

说"分区是为了消息均衡"
分区为了并行度 + 局部有序,不是均衡
认为扩容分区能无限提高消费者并行度
消费者数 ≤ 分区数,多了空转
只答"顺序写 + 分区",漏零拷贝
零拷贝是消费端最重要的性能亮点
认为 Kafka 用内存存储
Kafka 是磁盘追加写 + OS Page Cache,磁盘兜底
认为分区越多越好
分区多了 Rebalance 频繁、文件句柄爆炸

延伸追问

Kafka 分区只能增加不能减少,为什么?
减少分区会破坏 offset→消息的映射,已 commit 的 offset 失效;过多分区通过新建 Topic 迁移解决。
同一订单要保证顺序消费,分区数应该设多少?
分区数不决定 Key 路由,路由只由 hash(orderId) % numPartitions 决定;只需保证 Key 一致。
Topic 有 20 分区,消费者组只有 5 个消费者,每个消费者分到几个分区?
平均 4 个(RangeAssignor 或 CooperativeStickyAssignor 具体分配依算法)。
零拷贝的 sendfile 和 mmap 组合,为什么比单独 sendfile 更好?
sendfile 有 checksum CRC 的 CPU 开销,Kafka 用 mmap 让 CRC 校验同步完成,避免二次拷贝。
Producer 的 linger.ms 和 batch.size 怎么权衡?
linger.ms 越大攒批越好但延迟高;批量压缩率随 batch 增大而提升;生产上 5-50ms。

速查表

分区四大: 并行度 / 顺序性 / 扩展性 / 容错
Key 路由: hash(key) % numPartitions
高吞吐 8 层: 顺序 I/O + 零拷贝 + Page Cache + 分区并行 + 批量压缩 + 长轮询 + 索引 + 异步复制
零拷贝: mmap + sendfile,磁盘→内核→网卡,2 次拷贝
分区数: ≤ 100,只能增不能减,消费者数 ≤ 分区数

Anki 候选卡片

Q: Kafka 分区的四大作用?
A: 并行度上限 + 分区内有序 + 横向扩展 + 容错隔离
Q: Kafka 消费者数能超过分区数吗?
A: 不能,多出的消费者空转
Q: Kafka 高吞吐的 8 层机制?
A: 顺序 I/O + 零拷贝 + Page Cache + 分区并行 + 批量压缩 + 长轮询 + 索引优化 + 异步复制
Q: Kafka 零拷贝用什么系统调用组合?
A: mmap + sendfile,磁盘→内核→网卡 2 次拷贝
Q: Kafka 用磁盘还是内存存储?
A: 磁盘追加写 + OS Page Cache,磁盘兜底持久化
Q: Kafka 分区数可以减吗?
A: 不能,减少会破坏 offset→消息映射;过多分区通过新建 Topic 迁移

关联题目

  • ⚠️ 《Kafka 为什么有 Topic 还要用 Partition?》— Round 2 Q4, ⭐⭐⭐(只答了横向扩展,漏并行度、顺序性)
  • ⚠️ 《Kafka 为什么这么快?》— Round 2 Q5, ⭐⭐(只答 2/8,漏零拷贝)

关联知识

分区决定并行度和局部有序;高吞吐是 8 层机制协同的结果
流水线:多分区=多条并行流水线,Kafka 快是流水线+调度+搬运+打包一起上
✦ 记 忆 口 诀 ✦
分区四大:并行、有序、扩展、容错;高吞吐 8 层协同
关键可视化
分区四大作用
flowchart TD
  A[分区] --> B[并行度上限]
  A --> C[分区内有序]
  A --> D[横向扩展]
  A --> E[容错隔离]
  B --> F[消费者数 不能超过 分区数]
  C --> G[hash 加 key 加 mod numPartitions]
  D --> H[num.partitions 只能增不能减]
  E --> I[ISR 副本接管]
高吞吐 8 层机制
flowchart TD
  A[存储层] --> A1[顺序磁盘 I/O 追加写]
  B[网络层] --> B1[零拷贝 mmap 加 sendfile]
  C[内存层] --> C1[Page Cache 热数据在内存]
  D[并发层] --> D1[分区并行多 Broker 读写]
  E[调度层] --> E1[批量加压缩 linger.ms 加 batch.size]
  E --> E2[长轮询 避免空轮询]
  F[索引层] --> F1[Hash Index 加 Time Index 二分查找]
  G[副本层] --> G1[异步复制 ISR]
零拷贝 vs 传统拷贝
flowchart LR
  subgraph 传统 4 次拷贝
    A1[磁盘] --> B1[内核缓冲] --> C1[用户态] --> D1[内核 socket] --> E1[网卡]
  end
  subgraph 零拷贝 2 次拷贝
    A2[磁盘] --> B2[内核页] --> E2[网卡]
  end
知识关系

⬆️ 前置(Prerequisite)

kafka-message-structure

🔄 延伸(Extends)

暂无

⚡ 对比(Contrast)

暂无
🎯 概念 📏 规则 ⚠️ 误区 🔍 追问 ✨ 口诀 共 0 张卡,点击翻面