考察点
这道题出自字节跳动大数据工程师一面。Kafka 为什么快是经典题,面试官想确认你答得出完整链路:磁盘层面(顺序写、页缓存)、网络层面(零拷贝)、协议层面(批量、压缩)、架构层面(分区并行),而不是只记得"顺序写"三个字。追问常往"零拷贝具体省了哪几次拷贝"、"linger.ms 和 batch.size 怎么调"、"页缓存会不会丢数据"走。
参考答案
磁盘:把随机 IO 变成顺序 IO
Kafka 的核心洞察是:消息队列的读写模式天然是追加写、从头读,那就不需要数据库那种 B+ 树随机定位,直接每个 partition 对应一个 append-only 的日志文件(segment)。机械盘顺序写的吞吐可以到几百 MB/s,和随机写差几个数量级;SSD 上差距缩小但顺序写对擦写寿命依然友好。索引只有稀疏的 offset 索引和时间戳索引,定位时先二分索引文件再找消息,几乎不占写路径开销。
第二个磁盘层面的大招是页缓存(page cache)。Kafka 不自己堆缓存,而是直接依赖操作系统的页缓存:写消息时先写页缓存,由 OS 的 flush 策略异步刷盘;读消息时如果命中页缓存,数据根本不过磁盘。这意味着 Kafka 的"内存"就是机器剩余内存,broker 堆内存可以配得很小(几个 G 就够)。附带好处是 broker 进程重启后页缓存还在,恢复成本低。
网络:零拷贝
普通的数据发送路径是四次拷贝四次上下文切换:磁盘→内核缓冲区→用户态缓冲区→socket 缓冲区→网卡。Kafka 用 sendfile 系统调用,数据从页缓存直接拷贝到网卡缓冲区,完全绕过用户态,只剩两次拷贝(磁盘到页缓存、页缓存到网卡)。这就是为什么 Kafka 消费端压测时 CPU 占用很低——broker 基本不碰数据本身,只做文件描述符的搬运。这个机制的前提是消费的消息恰好是磁盘上原样存储的消息(不需要 broker 侧解压再转码),这也是 Kafka 把压缩压力推给生产者的原因之一。
协议:批量与压缩
Kafka 的高吞吐很大程度是"批"出来的。生产者侧,消息按 (topic, partition) 在内存里攒批,batch.size(默认 16KB)满了或 linger.ms 到了就发。linger.ms 是拿延迟换吞吐的关键参数:设 0 是消息一到就发,设 5-100ms 能让批次更满、请求数大幅下降。批次内消息用 LZ4 或 ZSTD 压缩(压缩率是吞吐的乘数,日志类文本 LZ4 轻松 3-5 倍),broker 收到压缩批次原样落盘,消费者拉到后在客户端解压——压缩解压的 CPU 成本被推到了集群外围,broker 保持轻量。
请求层面还有流水线化:生产者可以同时在飞多个请求(max.in.flight.requests.per.connection 默认 5),不阻塞等待。注意开幂等之后这个参数要控制在 5 以内保证顺序,这是个常被追问的细节。
架构:分区并行与 ISR 复制
分区是 Kafka 的并行度单位:一个 topic 的分区分散在多台 broker 上,生产者按 key 哈希或轮询打到不同分区,消费组内每个消费者独占若干分区,天然水平扩展。单机网卡打满了就加机器加分区,这是吞吐能线性扩展的架构基础。
复制机制上,副本同步走 leader-follower 拉取模型,acks 参数让吞吐和可靠性可调:acks=1 只等 leader 落页缓存,吞吐最高;acks=all 等 ISR 全部确认,配合 min.insync.replicas=2 是生产金融级配置,吞吐有损耗但可接受——因为副本复制同样是批量拉取,follower 的 fetch 也是攒批的。
消费者侧的配合
消费端同样是批量拉取:fetch.min.bytes 攒够多少字节才返回、max.poll.records 单次 poll 上限、fetch 请求本身可以等 fetch.max.wait.ms。消费吞吐低时先查这几个参数,而不是急着加消费者。另外消费组 rebalance 会停消费,高频 rebalance 是吞吐隐形杀手,sticky assignor 和合理的 session timeout 配置要跟上。
收个尾:一个统一视角
所有这些机制背后是同一个哲学:为"高吞吐、顺序访问、允许毫秒级延迟"这个特定场景做极致优化,放弃通用性。随机读少所以不需要 B+ 树;可以攒批所以把压缩和请求成本摊薄;数据不可变所以零拷贝无障碍。面试时如果能把这个设计哲学讲出来,比罗列五个机制更能体现深度。
可能的追问
- 页缓存异步刷盘会不会丢数据?会,所以单机层面 Kafka 不保证落盘持久性,可靠性靠多副本复制保证——这也是 acks=all + min.insync.replicas=2 成为生产标配的原因。
- 顺序写对 SSD 还重要吗?重要程度下降但依然有价值:减少写放大、降低 GC 压力,而且页缓存和批量机制的收益与磁盘类型无关。
- 分区数越多越好吗?不是。分区多了文件句柄、元数据、rebalance 时间、端到端延迟(acks=all 时要等的副本多)都上升,单 broker 上千分区就要开始警惕。