Kafka 面试题(2026-06-18)
【面试题】1. Kafka 的整体架构包含哪些核心组件?Producer、Broker、Consumer、ZooKeeper/KRaft 各负责什么?
【标准答案】Kafka 架构四个核心角色。Producer(生产者):负责把消息发到指定 Topic 的分区,内置分区器决定消息落哪个分区,支持异步攒批发送。Broker(服务节点):消息的实际存储和转发者,多个 Broker 组成集群,每个 Broker 管一部分分区,处理生产请求和消费拉取。Consumer(消费者):从 Broker 拉取消息,按消费组管理——同一消费组内的消费者分摊一个 Topic 的分区,做到水平扩展。ZooKeeper/KRaft(元数据协调):老版本用 ZK 存集群元数据(Broker 列表、分区分配、Controller 选举);3.3+ 版本用 KRaft 替代 ZK,元数据直接存在 Kafka 内部 Topic 里,简化了部署。简单类比:Producer 是写信的人,Topic 是收件箱,分区是收件箱里的格子,Broker 是邮局,Consumer 是收信的人,ZK/KRaft 是邮局的员工花名册和管理层。面试官爱追问为什么用 KRaft 替代 ZK——因为 ZK 是一个独立集群,运维成本高、元数据同步有延迟,KRaft 把元数据也存 Kafka 里,轻量且一致性更好。
【面试题】2. 自动提交位移和手动提交位移的区别是什么?什么业务场景必须用手动提交?
【标准答案】自动提交(enable.auto.commit=true):消费者在 poll() 时按 auto.commit.interval.ms 间隔自动提交位移,默认 5 秒一次。好处是省心、代码不用管,坏处是可能丢消息——比如你 poll 了 100 条消息,自动提交的位移已经到这 100 条后面了,但业务处理到第 50 条时进程挂了,剩下 50 条就丢了。手动提交分两种:同步提交 commitSync(),阻塞等待 Broker 确认,重试安全但影响吞吐;异步提交 commitAsync(),不阻塞但失败不会自动重试需要回调里处理。必须用手动提交的场景:一是处理逻辑有副作用(比如扣库存、发短信),必须消息处理完了再提交位移,保证 at-least-once;二是需要精确控制位移的场景,比如处理一批消息后手动按分区级别提交,避免 Rebalance 导致位移混乱。日常线上推荐异步提交 + 在 ConsumerRebalanceListener 的 onPartitionsRevoked 里补一次同步提交,兼顾吞吐和安全。
【面试题】3. Kafka 的消息日志是怎么存储在磁盘上的?Segment、.log、.index、.timeindex 分别干什么?
【标准答案】Kafka 的分区数据在磁盘上是一个目录,里面存的是"段文件"(Segment)——不是一个大文件无限追加,而是切成多个小段。每个 Segment 由三种文件组成:.log 文件(消息数据本体),按追加顺序存储,包含 offset、Key、Value、时间戳;.index 文件(偏移量索引),记录"某个 offset → .log 文件的哪个物理位置",用于消费者按 offset 快速定位,二分查找后直接 seek 到对应位置;.timeindex 文件(时间戳索引),记录"某个时间戳 → offset",用于按时间查找,比如你想从"昨天早上 8 点"开始重放。切分逻辑由 log.segment.bytes(默认 1GB)和 log.segment.ms(默认 7 天)控制,谁先满足就切新段。切段后旧段可以被清理线程按 retention 策略(时间或大小)删除。面试官爱追问为什么不存一个大文件——因为清理和定位都要性能代价,分段后可以直接删过期文件、查找也更快。类比数据库的 SSTable。
【面试题】4. 如何保证 Kafka 消息的全局有序和分区有序?各自有什么代价?
【标准答案】分区有序天然支持:只要生产者往同一个分区写入时保证顺序(同步发送或开启幂等),消费者单线程消费该分区就天然有序。代价:分区内只能一个消费者消费,无法并行提速。全局有序需要把所有消息都发到同一个分区(指定 Key 相同或者干脆不分区),消费者也是单线程消费。代价极重:全部消息单分区写入和消费,吞吐上不去,等于把一个分布式系统当成单机用,Kafka 的并行能力全浪费了。实际业务里真正需要全局有序的场景很少——电商订单按用户 ID 分区保证单用户有序就够了,不要求跨用户有序;金融流水按账户 ID 分区保证单账户有序即可。如果真有全局有序需求,Kafka 不是最优解,考虑用 RocketMQ 的顺序消息——它支持全局顺序 Topic 级别配置。总结:能用分区有序解决的不要搞全局有序,分区数就是你的并行度,搞全局有序等于放弃 Kafka 的核心优势。
【面试题】5. Range、RoundRobin、Sticky、CooperativeSticky 四种分区分配策略各自怎么工作?线上选哪个?
【标准答案】Range(默认):按 Topic 分区范围分配,分区数除以消费者数取模,不均衡时前面的消费者多分。致命问题是多 Topic 订阅时对不齐——比如 2 个消费者订阅 3 个 Topic,每个 Topic 2 分区,用 Range 可能第一个消费者拿 4 个分区第二个拿 2 个,严重倾斜。RoundRobin:把所有分区排成一个列表挨个轮询分给消费者,分配均匀,但 Rebalance 时会全部重新洗牌,抖动大。Sticky:第一次分配均匀,Rebalance 时尽量保持原有分配不变、只调整需要动的分区,减少分区迁移开销。CooperativeSticky(2.4+):在 Sticky 基础上做增量 Rebalance——过去是 Stop-The-World 模式,全体停消费重新分配;现在是分批迁移,消费者不全部停,一部分分区移走时其他分区继续消费。线上推荐:2.4 以下版本用 Sticky,2.4+ 开启 CooperativeSticky。如果团队还在用 Range 且多 Topic 订阅,赶紧切 Sticky——有一次线上事故就是因为 Range 导致某些消费者负载是别人的 3 倍,反复触发 Rebalance。
【面试题】6. 一条消息从生产到消费,怎么做到"不丢不重"?Producer → Broker → Consumer 三段分别怎么做?
【标准答案】"不丢"靠每段兜底,"不重"靠幂等和去重。第一段 Producer→Broker:丢消息的坑主要是 ack 没收到就以为成功了。配 acks=all(等所有 ISR 持久化才回报),min.insync.replicas≥2(至少两个副本确认),开启 retries 和 enable.idempotence(防止重试重复)。注意 delivery.timeout.ms 要大于 Flink checkpoint 间隔,不然事务中途过期。第二段 Broker 内部:靠副本机制保证——replication.factor≥3,unclean.leader.election.enable=false(不允许 ISR 外副本当选),只要 Leader 挂了并从 ISR 选新 Leader,数据就不会丢。第三段 Consumer→业务:丢消息主要在消费端——自动提交位移时消费者挂了会丢批。改成手动提交,消息处理完再 commit;重复消费靠业务幂等——数据库用唯一键或版本号,Redis 用 SETNX,或者用 Flink 的 Exactly-Once Sink。三段都做对了,就能实现端到端的"不丢不重"。面试官追问代价:acks=all + 副本同步增加了生产者延迟,手动提交增加了消费端复杂度。
【面试题】7. 线上消费 Lag 持续增长,积压了几千万条消息,你怎么快速处理?
【标准答案】消费积压别慌,分三阶段应急。第一阶段(分钟级止损):立刻扩容消费者实例,增加消费组的消费者数量(不能超过分区数);如果分区数不够,紧急增加 Topic 分区数让能加更多消费者。调整消费参数把单次拉取量拉大:max.poll.records 调到 500 以上,fetch.min.bytes 加大到 1MB,减少拉取往返次数。第二阶段(小时级追积压):如果正常消费逻辑太慢(比如每条消息要查 DB 或调 HTTP),临时写一个"降级消费"逻辑——跳过复杂业务处理,先把消息转发到另一个临时 Topic 或者直接写日志归档,让消费位移快速追上。或者用 Kafka 的 seek() 跳消息,放弃中间一部分数据(确认业务可接受)。第三阶段(复盘归因):查为什么积压——是上游生产突增?还是消费代码变慢(DB 慢查询、下游限流)?还是某次 Rebalance 导致全组短期停消费?找到根因后做长期优化:消费逻辑异步化、增加分区数、上流控保底。核心原则:先止损恢复水位,再事后归因,别在现场纠结根源。
【面试题】8. 生产环境出现过消息丢失,你怎么从头到尾排查?常见的丢消息点有哪些?
【标准答案】排查从"三段"逐一找。第一段 Producer:检查配置,acks 是不是设成了 0 或 1(只等 Leader 确认,Leader 挂了就丢);retries 是不是设了 0(网络抖动直接抛异常不管了);有没有 catch 了 send() 的异常但没处理。用 Kafka 生产者监控看 record-error-rate,异常率 > 0 说明有发送失败被吞。第二段 Broker:查 unclean.leader.election.enable 是不是 true(允许 ISR 外副本当选,丢数据风险);查 min.insync.replicas 是不是 1(等于没要求,Leader 写了就返回但 Follower 没同步);查 replication.factor 是不是 1(单副本,节点挂数据全丢)。看 Broker 日志有没有 LogTruncation 相关的异常。第三段 Consumer:查是不是用的自动提交(消息没处理完位移就提交了,挂了丢批);查有没有在 Rebalance 回调 onPartitionsRevoked 里做位移提交;查业务代码里是否有"消费完立刻删缓存"但没判断是否真正处理成功的逻辑。常见的丢消息检查清单就是:acks=0/1、单副本、自动提交、异常被吞——把这四个点排查完,90% 的丢消息问题都能定位。
【面试题】9. Kafka、RocketMQ、RabbitMQ 三者在架构设计、适用场景上的核心差异是什么?
【标准答案】三者的基因决定了各自的适用面。Kafka:以日志为核心的设计,消息是"不可变流",主打高吞吐、持久化、消息回溯。适用数据管道、流计算、埋点日志、CDC 场景,单机百万 TPS。核心代价是消息顺序性弱(只保证分区内有序)、延迟不是最低、对小消息场景偏重。RocketMQ:以"事务消息"和"顺序消息"为差异化卖点,阿里出品在金融电商场景打磨深。支持严格顺序消息(全局或分区),支持事务消息半消息机制。吞吐介于 Kafka 和 Rabbit 之间,单机十万级。适用于订单、支付、分布式事务协调这类对一致性要求高的业务。RabbitMQ:AMQP 协议,路由灵活(Exchange 绑定 Queue),支持优先级队列、死信、延迟队列等高级特性,消息消费完立刻删除。吞吐最低(单机万级),但功能最细粒度。适合企业级应用集成、任务队列、RPC 调用这类小体量但路由复杂的场景。一句话区别:Kafka 是"管道",跑数据;RocketMQ 是"引擎",跑业务;RabbitMQ 是"接线板",跑路由。
【面试题】10. 公司要从 0 搭建一套 Kafka 消息平台,你会怎么设计?考虑哪些方面?
【标准答案】分四个阶段做。第一阶段:需求摸底——搞清楚日均消息量、峰值 TPS、单条消息大小、消息保留时长、消费者数量和语言栈。这些决定了集群规模(几台、几核、几 TB 盘)、分区数和 retention。第二阶段:基础设施——至少 5 个 Broker 起步(3 个不够,挂 1 台 Controller 切换会影响可用性),跨机架部署加 broker.rack 做机架感知,磁盘用 SSD 做 JBOD 多盘挂载,选 KRaft 模式省掉 ZK。第三阶段:规范制定——Topic 命名规范(业务线.数据类型.落库名)、分区数规划(按峰值 QPS/单分区吞吐算)、消息格式规范(推荐 Avro + Schema Registry)、消费组命名规范、位移提交策略统一为手动提交。第四阶段:平台化——搭建 Kafka Manager 或 Cruise Control 做集群管理,Prometheus + Grafana 做监控,给业务方封装统一的 SDK(内置埋点、告警、重试、幂等),自动化 Topic 申请审批流程,做容量规划和磁盘告警。几个关键原则:别让业务方直接裸调 Kafka API,封装 SDK 统一治理;前期分区数宁多勿少;磁盘使用率不到 60% 就应该规划扩容;滚动升级要写在运维手册里。从 0 到 1,最难的不是搭集群(半小时就搭好了),而是规范和治理体系的落地。
生成时间:2026-06-18 22:42 覆盖考点:Kafka核心架构、位移提交机制、消息存储与日志分段、消息顺序性、分区分配策略、消息可靠性保证、消息积压排查与处理、数据丢失与重复消费、Kafka vs RocketMQ vs RabbitMQ对比、项目从0到1落地