Kafka 为什么这么快?
一则或许对你有用的小广告
欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书
《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于
Spring AI + Spring Boot 3.x + JDK 21...,查看介绍《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...,查看介绍;演示链接:http://116.62.199.48:7070/《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/
新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍
截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观
面试考察点
-
原理理解深度:面试官不想听你背名词,想知道的是你有没有真的理解顺序写、页缓存、零拷贝背后的操作系统原理,能不能讲清楚 “为什么这样快”。
-
操作系统功底:页缓存、sendfile、DMA、上下文切换,这些全是 OS 层面的知识。这道题答得好不好,直接暴露你计算机基础的扎实程度。
-
架构设计思维:批量、压缩、分区并行,这些是通用的性能优化思想。面试官想看你能不能把这些思想迁移到自己系统的设计里。
-
生产实战意识:知道这些机制后,会不会据此调优(比如 producer 的批量参数、分区数规划),这是 “会用” 和 “懂原理” 的分水岭。
核心答案
先甩结论,Kafka 的高吞吐是 6 大手段叠加 的结果:
| 优化手段 | 核心原理 | 解决的问题 |
|---|---|---|
| 顺序写磁盘 | 日志文件只追加,不随机写 | 磁盘随机 I/O 慢 |
| Page Cache | 读写都走 OS 页缓存,不进 JVM 堆 | 避免 GC、重启缓存不丢 |
| 零拷贝 | sendfile() 数据不经过用户态 |
减少拷贝和上下文切换 |
| 批量发送 | 攒一批再发(batch.size + linger.ms) |
摊薄网络往返开销 |
| 消息压缩 | 整批压缩(gzip/snappy/lz4/zstd) | 省带宽、省存储 |
| 分区并行 | Topic 拆成多个 Partition | 水平扩展、并行读写 |
前三条是磁盘 I/O 和网络传输层面的 “降本”,后三条是架构层面的 “增效”。面试时按这个顺序讲,层次感就出来了。
深度解析
一、顺序写:磁盘其实不慢,慢的是随机写
很多人有个误区,觉得磁盘一定比内存慢。其实要分场景看。Kafka 官方设计文档给过一组数据(6 块 7200 转 SATA 盘组 RAID-5):顺序写约 600 MB/s,随机写约 100 KB/s——差了约 6000 倍。
Kafka 的做法简单粗暴:每个 Partition 在磁盘上就是一批日志文件(Log Segment),消息来了只做一件事——追加到文件末尾,写完就返回(默认不等刷盘)。顺序写对磁盘太友好了:磁头不用来回寻道,写入还天然有序,OS 也好批量刷盘。
上图的流程拆开讲:
- 追加写:消息只往文件末尾追加,永远不修改已有数据,这是 Kafka 日志存储的根基
- 写 Page Cache 就返回:Broker 收到消息写进页缓存就算成功,不用等真正落盘(持久化靠多副本保证,后面追问会讲)
- OS 异步刷盘:操作系统攒一批后顺序刷下去,又是一个顺序写
顺便说一句,消费者消费消息也基本是顺序读(按 offset 从头到尾读),顺序读同样受益于磁盘预读(readahead)机制,一读就是一大块进缓存。
二、Page Cache:把缓存这事全权交给操作系统
Kafka 有个很反直觉的设计:它几乎不在 JVM 堆里缓存消息。数据读写的缓存,完全依赖操作系统的页缓存(Page Cache)。
这一步棋非常高明,一石三鸟:
- 躲开 GC:消息要是都缓存到 JVM 堆里,几十 GB 的堆 GC 停顿能把吞吐打成筛子。放 OS 页缓存,JVM 堆很小很干净
- 进程重启缓存不丢:页缓存属于操作系统,Broker 重启了缓存还在,消费者追数据照样能命中
- 读写都命中:Producer 刚写的消息在页缓存里,Consumer 紧跟着就读(实时消费场景),直接从内存返回,磁盘压根不用动
三、零拷贝:消费消息时的一记绝杀
这是这道题的最高潮部分,面试官最爱追问的就是它。
先看传统方式,Broker 把一个文件发给消费者要经历什么:
数据从内核态到用户态绕了一圈,可 Kafka 在这个流程里根本不需要 “看一眼” 消息内容——它就是个搬运工。于是 Kafka 用了 sendfile() 系统调用(Java 层对应 FileChannel.transferTo(),Kafka 源码里的调用路径是 PlaintextTransportLayer.transferFrom()):
对比一下这两张图:
- 传统方式:数据在内核缓冲区 → 用户缓冲区 → Socket 缓冲区 → 网卡之间倒腾,4 次拷贝(其中 2 次占 CPU)、4 次上下文切换
- 零拷贝:数据全程待在内核态,通过 DMA gather 技术直接从页缓存送到网卡,CPU 参与的拷贝次数为 0,上下文切换只剩 2 次
这个机制跟 Page Cache 是天作之合:Consumer 读的数据大概率就在页缓存里,sendfile 直接把缓存数据推给网卡,全程不占 CPU、不进用户态。大文件传输场景下,这优化是数量级的。
补一个细节:Kafka 的日志数据文件用 sendfile,而索引文件用的是 mmap(内存映射),因为索引文件小、随机访问频繁,正适合 mmap 的场景。
四、批量 + 压缩:网络开销,攒一波再付
Producer 发消息从来不一条一条发,攒够一批才发:
batch.size:一批的最大大小,默认 16 KBlinger.ms:最多等多少毫秒就发出去,默认 0(Kafka 4.0 起默认改成了 5ms,官方也意识到稍微等一下换吞吐太值了)
一批消息还会整体压缩后再传输,支持 gzip、snappy、lz4、zstd(2.1.0 版本引入)。批量 + 压缩的好处很直接:
- 摊薄固定开销:每次网络请求的协议头、RPC 往返时间是固定成本,一批 1000 条和一批 1 条,网络往返次数可能一样
- 压缩率更高:一批消息结构相似,整体压缩的压缩比远高于单条压缩
Consumer 端也一样,按批拉取(fetch.min.bytes、fetch.max.wait.ms 配合),双方都很省。
五、分区并行:横向扩展的基本盘
前面四条是单机层面的优化,这条是集群层面的。
一个 Topic 会被切成多个 Partition,分布在不同的 Broker 上:Producer 可以多线程并行往不同分区写,Consumer Group 里多个消费者各自认领分区并行消费。分区就是 Kafka 并行度的最小单位——想提吞吐?加分区、加机器就行,近乎线性地横向扩展。
六、几个加分细节
时间充裕的话,再补这几句,面试官眼睛会亮:
- Reactor 网络模型:Broker 端基于 Java NIO,1 个 Acceptor 线程接收连接,
num.network.threads(默认 3)个网络线程处理请求收发,num.io.threads(默认 8)个 IO 线程处理业务逻辑 - 稀疏索引:Log Segment(默认 1GB 一个)配索引文件,每写 4 KB(
index.interval.bytes)记一条索引,查找 offset 时二分定位,快且省内存 - V2 消息格式:0.11 版本后消息以 Record Batch 为单位存储,采用变长编码等优化,批次更紧凑,整批压缩也更高效
面试高频追问
-
零拷贝还用在哪?
Netty 的
FileRegion、RocketMQ 和 Nginx 的静态文件传输,底层都是sendfile。会举一反三,说明你是真懂。 -
Broker 不等刷盘就返回,断电不就丢数据了?
会丢。所以 Kafka 的持久化不靠单机刷盘,靠多副本:
acks=all+ 合理的min.insync.replicas,用副本换可靠。 -
Producer 想把吞吐拉满,怎么调?
linger.ms调到 5~10ms、batch.size调大、开压缩(推荐lz4或zstd)、acks=1(容忍丢数据的话)。 -
分区数越多越好吗?
不是。分区越多,Broker 端内存开销、文件句柄、副本同步开销都涨,Leader 切换也更慢。一般单机几千分区以内。
常见面试变体
- “Kafka 的高吞吐是怎么实现的?”(同款题,换个马甲)
- “讲讲零拷贝,Kafka 里怎么用的?”(单点深挖)
- “Kafka 和 RocketMQ 性能差异的原因?”(对比题:RocketMQ 需要支持消息查询、延时消息等,存储设计取舍不同)
记忆口诀
“写靠顺序页缓存,读靠零拷顺序读,传靠批量加压缩,扩靠分区并行度”
写:顺序写 + Page Cache;读:零拷贝 + 顺序读;传:批量 + 压缩;扩:分区并行。
总结
Kafka 快,没有什么黑科技,就是把每一层能省的开销都省了:磁盘层用顺序写 + 页缓存代替随机 I/O 和 JVM 缓存,网络层用零拷贝砍掉多余的数据搬运,传输层用批量 + 压缩摊薄开销,架构层用分区并行做横向扩展。面试时按 “磁盘 → OS → 网络 → 架构” 这条线讲下来,层次清晰,基本就稳了。
