← 返回题目列表

Kafka 为什么能做到这么高的吞吐量?

高频 困难 第 14 / 25 题 更新于 2026/07/28
消息队列Kafka高吞吐零拷贝

简化版

Kafka 高吞吐靠这几个关键设计:① 磁盘顺序写——消息顺序追加到日志文件,顺序写磁盘的速度接近甚至超过随机写内存,避免了随机 I/O 的寻址开销;② 零拷贝(Zero-Copy)——用 sendfile 让数据从磁盘直接经内核发到网卡,跳过用户态拷贝,消费时省掉多次数据复制;③ 分区并行——一个 Topic 分多个分区,多台 Broker、多消费者并行读写;④ 批量 + 压缩——生产者攒一批消息再发、并压缩,减少网络请求次数和传输量;⑤ Page Cache——读写都走操作系统页缓存,很多读请求直接命中内存。

详细版

五大高吞吐设计:

设计原理效果
顺序写磁盘消息只追加(append)到分区日志末尾顺序 I/O 无寻址,速度极快
零拷贝sendfile 磁盘→内核→网卡,跳过用户态消费时省去多次拷贝和上下文切换
分区并行Topic 分多 Partition,分散到多 Broker读写并行,水平扩展
批量 + 压缩生产者攒批发送、批量压缩(gzip/snappy/lz4)减少网络请求数和传输量
Page Cache读写走操作系统页缓存读多命中内存,写先入缓存异步刷盘

完整版教学

一、顺序写磁盘:颠覆”磁盘慢”的直觉

很多人以为「Kafka 快是因为用内存」,其实 Kafka 的消息是持久化到磁盘的,但依然快——关键在于它用的是顺序写(append-only)

Kafka 每个分区是一个只追加的日志文件(commit log),新消息永远追加到文件末尾,从不修改、不随机插入。而磁盘的性能瓶颈主要是随机 I/O 的磁盘寻址(磁头移动/寻道)——随机写要不停寻址,极慢;而顺序写不用寻址,磁头一直往后写,速度惊人:顺序写磁盘可达几百 MB/s,甚至超过随机写内存

所以 Kafka「利用磁盘顺序写」这个特性,既获得了持久化(数据不丢),又拿到了接近内存的写入速度。这是它高吞吐的地基。

二、零拷贝:消费时省掉多次数据搬运

消费者从 Kafka 拉消息,本质是「把磁盘上的日志文件数据发到网络」。传统方式要经过 4 次拷贝、2 次上下文切换:

  1. 磁盘 → 内核缓冲区(DMA 拷贝);
  2. 内核缓冲区 → 用户态应用缓冲区(CPU 拷贝);
  3. 用户态 → 内核 socket 缓冲区(CPU 拷贝);
  4. socket 缓冲区 → 网卡(DMA 拷贝)。

中间两次「内核↔用户态」的拷贝纯属浪费——数据只是路过应用、没做任何处理。

零拷贝(Zero-Copy) 用操作系统的 sendfile 系统调用,让数据从磁盘(内核)直接送到网卡(内核 socket),跳过用户态的两次拷贝和上下文切换。数据不再经过应用进程的内存。这大幅减少了 CPU 消耗和内存带宽占用,消费吞吐显著提升。

三、分区并行:水平扩展的基础

一个 Topic 被分成多个分区(Partition),分区可以分布在**不同的 Broker(服务器)**上。这带来并行:

  • 生产并行:不同分区可以同时被写入。
  • 消费并行:一个消费者组里,不同消费者消费不同分区,并行消费
  • 水平扩展:加机器、加分区就能线性提升整体吞吐。

分区是 Kafka 并行和扩展的基本单位——单机顺序写已经很快,再乘以多分区多机并行,总吞吐就非常高。

四、批量 + 压缩:减少网络开销

网络请求是有固定开销的(每次请求都有握手、协议头等成本)。如果一条消息发一次请求,海量小请求的开销会成为瓶颈。Kafka 的优化:

  • 批量发送:生产者不是来一条发一条,而是攒一批batch.size 或等 linger.ms 时间)再一次性发送。用少量大请求代替大量小请求,摊薄网络开销。
  • 压缩:批量的消息可以整体压缩(gzip、snappy、lz4、zstd)后再传输,减少网络带宽占用。压缩在生产者端做、消费者端解压,Broker 存的也是压缩数据(省磁盘)。批量越大,压缩率越好。

批量 + 压缩显著提升了单位网络带宽能传输的消息数。

五、Page Cache:让操作系统帮忙缓存

Kafka 不自己在 JVM 堆里维护消息缓存,而是充分利用操作系统的 Page Cache(页缓存)

  • 写入:消息写入其实是写到 Page Cache(内存),由操作系统异步刷盘——写入方感觉是「写内存」,很快。
  • 读取:读消息时,如果数据还在 Page Cache 里(刚写入不久的热数据),直接从内存读,不用访问磁盘。而消费者往往消费的是刚生产的新消息,命中率很高。

好处:

  • 避免 JVM GC:缓存交给操作系统管理,不占 JVM 堆,没有大堆 GC 问题。
  • 重启不丢缓存:Page Cache 由 OS 管理,Kafka 进程重启后缓存还在。
  • 读写都受益:写走缓存快,读多命中缓存快。

六、常见误区与追问

考点正确口径
顺序写追加写日志,减少随机 IO
Page Cache利用 OS 缓存和批量刷盘
批处理/压缩/零拷贝减少网络包、磁盘写和 CPU 拷贝
producer batch 1000 records
-> append to log segment sequentially
-> page cache
-> consumer fetch
-> sendfile / zero-copy path

Kafka 快不是单点技巧,而是顺序 IO、批处理、分区并行和零拷贝组合起来的结果。

  • 误区:Kafka 快是因为全部放内存。 Kafka 主要依赖顺序写磁盘和 Page Cache,不是把所有消息都存在 JVM 内存。
  • 误区:批量越大越好。 批量大提升吞吐但增加延迟和内存占用,要按业务调 batch.size 和 linger.ms。
  • 误区:分区越多吞吐无限增加。 分区过多会增加文件句柄、复制、选举和调度成本。
  • 追问:顺序写为什么快? 磁盘顺序写避免大量寻道,SSD 上也能减少写放大和元数据开销。
  • 追问:零拷贝在 Kafka 哪体现? 消费者拉取日志时可利用 sendfile 从页缓存发送到 socket,减少用户态拷贝。
  • 追问:压缩为什么可能提升吞吐? 压缩减少网络和磁盘字节数,代价是 CPU 消耗。

七、加强记忆

Kafka 高吞吐靠五大设计:① 磁盘顺序写——消息只追加到分区日志末尾,顺序 I/O 无寻址开销,速度接近甚至超过随机写内存(既持久化又快);② 零拷贝——用 sendfile 让数据从磁盘内核直达网卡,跳过用户态两次拷贝和上下文切换,消费更快;③ 分区并行——Topic 分多 Partition 分散到多 Broker,读写并行、水平扩展;④ 批量 + 压缩——生产者攒批发送并压缩,减少网络请求数和传输量;⑤ Page Cache——读写走操作系统页缓存,避免 JVM GC、读多命中内存。记忆锚点:顺序写、零拷贝、分区并行、批量压缩、页缓存——磁盘也能飞快。