超参数科技 后端开发 一面
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 实习相关:介绍一下你的实习经历。
- Kafka 与其他消息队列的区别是什么?
- Kafka 的性能为什么这么好?
- Kafka 为什么支持高并发(从设计角度出发)?
- 如何协调 Kafka 的消费者?
《参考解析》
Kafka 与其它 MQ 的区别要按「定位」而不是「功能表」来答。Kafka 的原始定位是分布式提交日志,为流式数据设计:消息持久化到磁盘并按分区顺序追加,消费后不删除、靠 offset 记录消费位置,因此支持多消费者组各自独立消费同一份数据、支持消息回溯重放。RabbitMQ 是传统消息代理,以队列和交换机为核心,路由能力(direct/topic/fanout/headers)最强,消息被消费后即删除,更适合任务分发和 RPC 式的业务解耦。RocketMQ 是阿里巴巴为电商场景打磨的,事务消息、延迟消息、消息轨迹这些业务特性开箱即用,吞吐与 Kafka 同量级,延迟消息的支持比 Kafka 原生好。Pulsar 采用计算存储分离架构(Broker + BookKeeper),支持多租户和分层存储,扩展性上更有优势。选择上常见的口径是:日志采集、流式计算、需要重放的场景用 Kafka;复杂路由和低延迟任务队列用 RabbitMQ;需要事务消息、延迟消息的业务用 RocketMQ。顺带要说清 Kafka 的弱项:原生不支持延迟消息和消息优先级,topic 数量过多时元数据与 rebalance 成本会上升。
Kafka 性能好的原因要落到四个具体机制上。 ① 顺序写磁盘:每个分区是一个只追加的日志段文件,写入是纯追加,避免了随机 I/O;现代磁盘顺序写的吞吐接近内存带宽的量级。② 页缓存 + 零拷贝:读写都走操作系统的 page cache,Kafka 自己不做应用层缓存;消费时用 sendfile(对应 Java 的 FileChannel.transferTo)把数据从页缓存直接送到网卡,省掉「内核态→用户态→内核态」的两次拷贝和两次上下文切换。③ 批量与压缩:生产端把消息按 batch.size 和 linger.ms 攒批发送,broker 以批为单位落盘,网络和磁盘都是批操作;配合 snappy/lz4/zstd 压缩,压缩是按批做的,压缩比远高于单条压缩。④ 分区并行:topic 分成多个分区分布在不同 broker 上,读写都是分区级并行,吞吐随分区数(在机器资源允许范围内)线性扩展。可以再补两点工程细节:broker 用 sendfile 后不需要把消息读进 JVM 堆,避免了 GC 压力;索引文件(.index 稀疏索引 + .timeindex)让按 offset 或时间戳定位都很快。
「Kafka 为什么支持高并发(设计角度)」与上一题部分重叠,但要把重点放在并发模型上:① 网络层用 Reactor 多路复用,一个 Acceptor 线程负责建连,多个 Processor 线程(num.network.threads)负责收发数据,请求被放进共享队列由 num.io.threads 个处理线程消费,整体是「少量线程 + 大量连接」而不是一连接一线程;② 分区是并行的最小单位,生产端可以并发写多个分区、消费端每个分区由一个消费线程负责,多消费者并行消费不同分区;③ 无状态的 broker 加上分区副本机制,让水平扩展只需增加 broker 并迁移分区;④ 客户端侧有独立的发送与拉取线程、异步发送 + in.flight.requests.per.connection 允许流水线,避免客户端成为瓶颈;⑤ 顺序写 + 批量 + 零拷贝把单分区单线程的路径做到极短,减少了锁竞争(Kafka 只在分区级别加锁)。答题时把「并发的粒度是分区、不是消息」这句话点出来,很多候选人会漏掉这个关键设计。
消费者协调要讲清消费者组、rebalance 和 offset 管理三块。同一个消费者组内,每个分区只会被组内一个消费者消费,实现并行消费且不重复;组内的 leader 消费者负责根据订阅关系和分区数制定分配方案,coordinator(由 broker 担任,靠 __consumer_offsets 这个内部 topic 承载组状态)负责协调。触发 rebalance 的事件包括:消费者加入/离开/崩溃(靠心跳和 session.timeout.ms 检测)、订阅的 topic 分区数变化、订阅关系变化。分配策略有 Range(按 topic 逐个范围分,topic 多时容易不均)、RoundRobin、Sticky(尽量保留上次分配,减少分区迁移)、CooperativeSticky(增量式 rebalance,避免全组停摆)。要重点说明 Kafka 的演进:早期 rebalance 是「Stop The World」——所有消费者停止消费、全部重新分配,分区多、消费者多时会持续几十秒;2.4 起引入 CooperativeSticky + 增量协作式 rebalance,通过两轮协议(第一轮只撤销需要移交的分区)避免全组停顿。运维上要防的错误是:max.poll.interval.ms 设得比单批处理时间短会导致消费者被踢出组、引发反复 rebalance,所以要么增大该值、要么降低 max.poll.records。offset 提交有自动和手动两种,手动 commitSync 更可控;要做到「至少一次 + 幂等」就把提交放在业务处理成功之后,消费端按业务主键去重。