极高 困难
Kafka高性能原理#
一句话答案#
Kafka 高性能五大因素:顺序写磁盘 + 零拷贝(sendfile)+ 分区并行 + 批量发送 + 消息压缩。
核心要点
Kafka 能达到百万级 TPS,核心依赖三个底层优化(顺序写、PageCache、零拷贝),再加上批量、压缩、分区并行:
1. 顺序写磁盘(Sequential Write)
随机写磁盘:磁头每次都要寻道到新位置 → 约 10ms/次 → 100 IOPS
顺序写磁盘:磁头沿磁道连续写 → 约 600MB/s 吞吐
顺序写比磁盘随机写快几个数量级(HDD 顺序写可达数百 MB/s,随机写只有几 MB/s),但并不接近内存
Kafka 的 Partition 是一个只追加(append-only)的日志文件:
→ 生产者发来的消息追加到文件末尾
→ 永远不修改已写入的内容
→ 纯顺序写,磁盘 IO 极高效plaintext2. PageCache(操作系统页缓存)
Kafka 写消息流程:
消息 → PageCache(内存)→ 操作系统异步刷盘 → 磁盘
不走 Java 堆内存(避免 JVM GC),直接操作 OS 的 PageCache
好处:
消费者消费"热数据"时,直接从 PageCache 返回(不读磁盘)
PageCache 由 OS 管理,进程重启后 PageCache 还在(不像 JVM 堆)plaintext3. 零拷贝(Zero-Copy,sendfile 系统调用)
传统 read + write 发送(4 次拷贝 = 2 次 DMA + 2 次 CPU,4 次上下文切换):
磁盘 → 内核 PageCache → 用户空间(read)→ Socket Buffer → 网卡(send)
sendfile 零拷贝(2 次上下文切换,不经过用户空间):
磁盘 → 内核 PageCache → 网卡
网卡支持 SG-DMA 时只有 2 次 DMA 拷贝、0 次 CPU 拷贝(Socket Buffer 只放描述符);
不支持时多 1 次 PageCache → Socket Buffer 的 CPU 拷贝
Kafka 消费者读取消息时调用 sendfile,数据不需要拷贝到用户空间,
直接从 PageCache 传到网卡,减少 CPU 拷贝开销和上下文切换plaintext其他优化:
- 批量发送:生产者将多条消息批量打包成一个请求(RecordBatch),减少网络往返
- 消息压缩:支持 gzip/Snappy/LZ4/Zstd 压缩,减少网络传输量
- Partition 并行:Topic 分为多个 Partition,不同 Partition 并行读写,线性扩展吞吐量
面试回答(2分钟版)
Kafka能做到百万级TPS主要靠五个方面的优化。第一是顺序写磁盘,Partition本质是append-only的日志文件,消息只追加到末尾不做随机写,磁盘顺序写可达几百MB/s,比随机写快几个数量级。第二是PageCache,Kafka写消息先写入操作系统的PageCache由OS异步刷盘,不走Java堆内存避免GC影响,消费者读取热数据时直接从PageCache返回不需要读磁盘,而且进程重启后PageCache仍然在。第三是零拷贝,消费者拉取消息时Kafka使用sendfile系统调用,数据从PageCache直接传到网卡不经过用户空间,省掉一次CPU拷贝和两次上下文切换(网卡支持SG-DMA时CPU拷贝降为0)。第四是Partition并行,一个Topic分成多个Partition,不同Partition可以并行读写,吞吐量线性扩展,但Partition数量不是越多越好,过多会增加Leader选举时间和文件句柄消耗。第五是批量加压缩,生产者将多条消息打包成RecordBatch批量发送,配合Snappy或LZ4压缩减少网络IO。这五点协同作用让Kafka在大数据场景下吞吐量远超传统MQ。
追问与易错
追问方向:
- “顺序写为什么快?”→ 省掉磁头寻道和旋转等待,还能配合 OS 预读和写合并,顺序 IO 吞吐远高于随机 IO
- “零拷贝具体是哪个系统调用?”→ sendfile(Java 里是
FileChannel.transferTo),跳过用户态拷贝;开启 SSL/TLS 时数据要在用户态加密,用不上 sendfile 零拷贝 - “Partition 数量越多越好吗?”→ 不是,过多增加选举时间/文件句柄/内存
易错点:
- ❌ “Kafka 快是因为内存操作”——Kafka 是磁盘存储,快在顺序写+Page Cache+零拷贝
- ❌ “增加 Partition 就能线性提升性能”——有上限,过多反而降低