Skip to content

Kafka 面试题(2026-06-18) ​


【面试题】1. Kafka 的 HW(高水位)和 LEO 分别是什么?两者之间的关系? ​

【标准答案】HW(High Watermark)是分区内消费者能读到的最新消息偏移量,HW 之前所有消息都已提交,对所有消费者可见。LEO(Log End Offset)是分区日志的下一条待写入消息的偏移量,代表当前日志末尾。关系很简单:HW = ISR 中所有副本 LEO 的最小值,也就是说 HW 受最慢的那个 ISR 副本约束。Leader 维护所有 ISR 副本的 LEO,取最小值更新 HW,通过 fetch 响应把这个 HW 带给 Follower,Follower 同步更新自己的 HW。这个设计保证了:只有在所有 ISR 都同步完的消息才被认为"已提交",消费者读不到未同步的数据。面试官爱追问:为什么不用 Leader 自己的 LEO 当 HW?——因为 Leader 宕机后可能有已写但未同步的消息,新 Leader 必须截断到 HW,如果用 LEO 会丢数据。

【面试题】2. 消费者 poll() 方法的底层流程是怎样的?从拉取到返回经历了什么? ​

【标准答案】poll() 不是直接去 Broker 拉数据,底层其实是一个"拉取→反序列化→分配"的流水线。具体流程:消费者的 Fetcher 线程在后台一直发 fetch 请求,从各分区 Leader 的当前位置往后拉数据,拿到的是原始字节;拉到后放进 CompletedFetch 队列缓存,这里面已经是反序列化好的 ConsumerRecord;poll() 被调用时只是从本地缓存队列里取,取完就返回,不阻塞等待网络。真正决定延迟的是 fetch 参数:fetch.min.bytes 设太小拉不到数据又频繁请求(浪费网络)、设太大延迟高;fetch.max.wait.ms 是 Broker 凑数据的最大等待时间,配合 min.bytes 攒批后返回;max.partition.fetch.bytes 控制单分区一次拉多少数据,设太小单次 poll 拿到的消息少,吞吐上不去。线上调优就围绕这三个参数:吞吐优先就拉大 fetch.min.bytes 和 max.partition.fetch.bytes,延迟优先就缩 fetch.min.bytes 和 max.wait.ms。

【面试题】3. Kafka Topic 分区数能减少吗?分区扩容有什么影响和注意事项? ​

【标准答案】分区数只能增不能减,这是 Kafka 设计的硬约束。一旦减少分区,那部分分区的数据全丢、消费偏移全乱,不可逆。分区扩容本身无感——Broker 创建新分区目录、Controller 广播元数据,业务不停机。但扩容有副作用:第一,如果有 Key 的消息靠哈希路由,分区数变了相同 Key 可能落到不同分区,破坏局部有序;第二,新分区无历史数据,之前累积的数据消费不到;第三,分区越多 Controller 元数据越大,Rebalance 耗时越长,单 Broker 建议别超过 2000-4000 个分区。扩容原则是宁多勿少——前期根据预测峰值 QPS 一次给足,比如目标单分区吞吐 10MB/s,峰值 100MB/s 就设 10 个分区,永远比后期扩容简单。真要扩容记得先通知消费者组,让他们有预期。

【面试题】4. Kafka 副本间的数据同步到底怎么进行的?Follower 拉取和 Leader 响应的完整过程? ​

【标准答案】副本同步是"拉模型"——Follower 主动从 Leader 拉,不是 Leader 推。流程:Follower 每隔 replica.fetch.wait.max.ms(默认 500ms)发一个 fetch 请求,带上自己的 LEO 告诉 Leader "我已经同步到哪了"。Leader 收到后,从 Follower 当前的偏移量位置往后读本地日志,最多拉 replica.fetch.max.bytes 的数据,打包响应返回。Follower 收到数据追加到本地日志,更新 LEO → 然后 Leader 从所有 Follower 的 LEO 里取最小值更新 HW → Leader 在下一次 fetch 响应里把新 HW 带给 Follower → Follower 更新自己的 HW。整个链路是 Follower→Leader→Follower 的循环。两个关键超时:如果 Follower 超过 replica.lag.time.max.ms(默认 30s)没拉取或落后太多,就被踢出 ISR。这个拉模型的好处是 Follower 自己控制同步速度,不会出现网速慢的 Follower 被打爆的情况,坏处是 Leader 宕机时最后一批数据可能没来得及被 Follower 同步。

【面试题】5. Kafka 的 GroupCoordinator 是什么?它怎么管理消费组的? ​

【标准答案】GroupCoordinator 是 Broker 端负责管理消费者组的组件,每个消费组 hash 后落到一台 Broker 上由该 Broker 的 Coordinator 处理,这个 Broker 就是该组的"组长 Broker"。主要做四件事:一、处理消费者入组请求(JoinGroup),记录成员信息和订阅 Topic;二、选出一个消费者当 Group Leader,由它执行分区分配算法并返回分配方案;三、接收 Group Leader 的分配结果,把方案下发给所有消费者;四、持续收心跳(Heartbeat),超时踢出消费者触发 Rebalance。心跳机制在 2.3+ 解耦了——session.timeout.ms 控制心跳超时踢人时间,max.poll.interval.ms 控制两次 poll 之间的最大间隔,避免消费者处理慢触发 Rebalance。Coordinator 的故障处理:如果它所在的 Broker 挂了,消费者心跳超时后触发现有 Coordinator 失效,所有消费者重新找一台 Broker 建新 Coordinator、重新 JoinGroup 触发一次全量 Rebalance——所以 Coordinator 挂了影响面很大。

【面试题】6. 线上消费者频繁 Rebalance 但成员数量没变、分区数也没变,你怎么排查? ​

【标准答案】成员数没变、分区没扩容还频繁 Rebalance,根因几乎一定是消费者处理消息太慢触发了 max.poll.interval.ms 超时。排查路径:第一步看 Kafka 消费端的日志找 "Member xxx sent LeaveGroup" 或者 "Removing member xxx because poll timeout",确认是被踢的。第二步看监控里消费者的 max.poll.interval 有没有逼近配置的阈值(默认 5 分钟)。第三步定位具体哪段业务代码慢——是不是下游 DB 慢查询、HTTP 调用超时、JVM Full GC 导致消费者线程假死。解决方向:一、优先优化消费逻辑,把耗时操作异步化或批量化;二、如果消费逻辑本身就慢,调大 max.poll.interval.ms 到 10-15 分钟;三、用 Cooperative Sticky 策略做增量 Rebalance,即使 Rebalance 了也只移少量分区;四、检查下是不是消息体太大、反序列化耗时高——加 max.partition.fetch.bytes 限制单次拉取量。记住:频繁 Rebalance 是结果不是原因,根因在消费耗时。

【面试题】7. Kafka 事务的隔离级别 read_committed 和 read_uncommitted 有什么区别?什么时候必须用 read_committed? ​

【标准答案】read_uncommitted(默认):消费者能读到所有消息,包括未提交的事务消息和已中止的事务消息。好处是延迟低,坏处是可能读到事务回滚后的脏数据。read_committed:消费者只能读到已提交事务的消息,未提交和已中止的消息会被自动过滤掉。实现原理是 Broker 端维护一个事务状态缓存,消费者拉取消息时 Broker 对照缓存,把未提交的消息拦截不返回。代价是延迟增加——因为消费者必须等到事务提交后才能读到消息,事务没提交消息就一直"挂着"。什么时候必须用 read_committed?典型场景是"下游消费依赖事务原子性",比如订单创建事务同时写订单 Topic 和通知 Topic,如果下游从通知 Topic 读到消息就去查订单,但事务还没提交、订单不存在,就出 bug 了。用了 read_committed 就能保证读到的都是确认无误的数据。大部分场景用 read_uncommitted + 业务层幂等就够,除非你真的强依赖跨 Topic 的一致性读取。

【面试题】8. 10 万 TPS 的 Kafka 集群,OS 层面怎么调优?文件系统、磁盘、网络怎么配? ​

【标准答案】OS 调优是 Kafka 高性能的底座,很多人只调 JVM 参数不管 OS。文件系统选 XFS 或 ext4,千万别用 NFS/网络文件系统,性能差几十倍。磁盘优先 SSD 或 NVMe,做 JBOD 模式(多盘挂载到不同目录,Kafka 自己管理不用 RAID),日志目录配置时把多个磁盘路径写进 log.dirs,Kafka 自动按分区分散写。挂载时加 noatime 选项,避免每次读文件还更新访问时间戳。网络层:首先把 somaxconn 和 tcp_max_syn_backlog 调大(sysctl),应对高并发连接;net.core.rmem_max 和 wmem_max 调大到 1MB 以上,Broker 的 socket.send.buffer.bytes 也配合拉大,减少小包传输次数;如果可以开巨型帧(Jumbo Frame 9000 MTU),大消息场景吞吐提升明显。内存:vm.swappiness 设为 1,尽量用物理内存不用 swap。文件句柄:ulimit -n 至少 10 万以上,Broker 分区多、连接多会导致文件句柄暴增。总结:磁盘用多盘 JBOD + noatime,网络调 buffer + 巨型帧,内存禁 swap,句柄拉到顶。

【面试题】9. Kafka 集群要做不停机滚动升级,需要注意什么?完整流程是怎样的? ​

【标准答案】滚动升级是线上运维必会的操作,核心原则是"一个 Broker 一个 Broker 来,每步都验证"。流程分七步。一、升级前确认协议兼容性——Kafka 版本升级关键是 inter.broker.protocol.version 和 log.message.format.version 两个参数,一般是先升 Broker 软件,协议版本暂用旧的,全部 Broker 升完再切新协议。二、确认集群状态健康:underReplicatedPartitions=0,无异常的 Controller 切换,所有 ISR 正常。三、选一台非 Controller 的 Broker 关流量——在负载均衡层摘掉或逐步迁移 Leader 分区到其他 Broker。四、等该 Broker 所有分区都同步完、Lag 为零后,停服务升级。五、升级后启动,验证日志无异常、重新加入集群后抢占分区 Leader 正常。六、等该 Broker ISR 恢复完毕、Lag 消除后,再操作下一台。七、所有 Broker 升级完,再分步升级 inter.broker.protocol.version。几个坑:跨大版本升级(比如 1.x→3.x)不能跳,必须逐大版本升级;升级期间可能有短暂的 Leader 切换导致分区不可写 1-2 秒,选业务低峰期;每次操作前先做好备份,出问题能回滚。集群越大滚动时间越长,别忘了通知业务方。

【面试题】10. 线上一个 Topic 消息量突然暴增,磁盘使用率从 60% 飙到 85%,你怎么处理? ​

【标准答案】磁盘告急是 Kafka 运维的经典意外。紧急处理按优先级来:第一步先确定哪台机器、哪个 Topic 在涨——用 kafka-log-dirs.sh 查各 Broker 磁盘使用量分布,锁定涨得最快的目录。第二步临时止损:立刻缩短该 Topic 的 retention.ms(比如从 7 天缩到 2 天),Kafka 后台清理线程会开始删除过期分段释放空间,这是最快的手段而且不丢近期数据。如果还是不够,第二步并行扩容——给这台 Broker 加挂磁盘,修改 log.dirs 配置把新盘加进去,用 kafka-reassign-partitions.sh 把部分分区数据迁移过去,迁移过程不停机。第三步排查为什么暴增:是不是上游业务出了 bug 在死循环写消息?查该 Topic 的生产者 QPS 指标和消息体大小异常;是不是某个消费者消费暂停导致没消费出去?查消费 Lag。第四步长期治本:给该 Topic 加分区数分散数据到更多磁盘;设磁盘使用率告警阈值(比如 75% 预警、85% 严重告警);做容量规划时留 30% buff,别卡着磁盘容量上限配。紧急场景别慌,优先用 retention 参数腾空间,再做事后归因。


生成时间:2026-06-18 22:29 覆盖考点:消息存储(HW/LEO)、消费者机制(poll底层流程)、主题/分区扩容影响、副本同步底层机制、Broker核心(GroupCoordinator)、消费组Rebalance排查、事务隔离级别、OS层性能调优、日常运维(滚动升级)、故障排查(磁盘告急)