这不是一份单纯背概念的 Kafka 八股文,而是把面试中真正高频的问题、容易被追问的点,以及生产场景里经常遇到的坑串起来整理成的一套复习资料。
看完上篇,读者不只是知道"Kafka 是什么",更重要的是能回答清楚:为什么项目里要用 Kafka、Kafka 为什么能扛高吞吐、生产者怎么保证消息可靠、消费者 offset 出问题会带来什么影响、Leader/Follower/ISR/HW 这些概念在真实故障里到底有什么用。
看完上篇,你能掌握:
-
Kafka 的核心价值:削峰、异步、解耦。
-
Producer 可靠性:ack、幂等前置、发送异常、写入优化。
-
Consumer 基础机制:offset、提交方式、Pull 模式、宕机恢复。
-
存储与性能原理:顺序写、Page Cache、零拷贝、segment、稀疏索引。
-
副本与一致性基础:ISR、OSR、AR、HW、LEO、Leader 故障处理。
-
高频追问链路:每道题后面都整理了面试官可能继续问的问题,帮助你从"会背"过渡到"能讲清楚"。
1. 为什么要使用 Kafka?
Kafka 常见使用原因主要有三个:
1.削峰填谷。
当上游流量突然增大时,Kafka 可以作为中间缓冲层,避免下游服务被瞬时流量打垮。
2.异步解耦。
有些业务不需要同步等待结果,例如创建任务、发送通知、数据同步等,可以先写入 Kafka,再由消费者异步处理,从而提升接口响应速度。
3.系统解耦。
生产者只负责发送消息,不需要知道具体有哪些消费者;消费者也只关注自己订阅的 topic,降低系统之间的直接依赖。
面试回答模板:
>Kafka 主要解决削峰、异步、解耦的问题。比如上游流量突增时,Kafka 可以先承接消息,消费者按照自己的处理能力慢慢消费;同时生产者和消费者通过 topic 交互,降低系统耦合。
可能会被追问:
1.Kafka 和普通 MQ 的区别是什么?
答:Kafka 更偏高吞吐、分布式日志存储和流式处理,消息会持久化在磁盘中,并通过 topic、partition、offset 来管理消费进度。传统 MQ 更偏业务消息投递,通常更强调路由、事务消息、延迟消息等业务能力。
2.Kafka 为什么适合日志、埋点、大数据场景?
答:因为这些场景通常数据量大、写入频繁、允许异步处理,而且更关注吞吐量。Kafka 的顺序写、分区并行、批量发送、磁盘持久化都很适合这类数据管道。
3.如果下游一直消费不过来,Kafka 只是缓冲,最终还是会堆积,怎么办?
答:要先定位消费慢的原因,比如消费者异常、下游数据库慢、单条消息处理耗时长、分区数限制并发等。短期可以扩容消费者或临时扩分区 topic,长期要优化消费逻辑、下游能力和告警机制。
2. Kafka 为什么快?
Kafka 快主要不是因为它把所有数据都放在内存里,而是因为它很好地利用了操作系统和磁盘特性。
核心原因:
1.顺序写磁盘。
Kafka 写消息时主要是追加写 log 文件,顺序写性能远高于随机写。
2.Page Cache。
Kafka 大量依赖操作系统页缓存,而不是把数据都放在 JVM 堆内,减少 GC 压力。
3.零拷贝。
消费消息时可以通过零拷贝减少用户态和内核态之间的数据复制次数。
4.分区并行。
topic 可以拆成多个 partition,不同 partition 可以分布在不同 broker 上,从而提升并发吞吐。
5.Segment 文件和稀疏索引。
Kafka 将 partition 日志拆成多个 segment,并通过 offset index 快速定位消息。
6.Pull 模式。
消费者按自己的能力拉取数据,避免 broker 主动 push 导致消费者被压垮。
面试回答模板:
>Kafka 快的核心是顺序写、Page Cache、零拷贝和分区并行。写入时追加到 log 文件,充分利用磁盘顺序写;读取时依赖操作系统页缓存和零拷贝减少数据复制;同时 topic 分区可以并行读写,所以吞吐量很高。
可能会被追问:
1.零拷贝具体减少了哪些拷贝?
答:传统读取文件并发送到网络,大致需要磁盘到内核缓冲区、内核缓冲区到用户缓冲区、用户缓冲区再到 socket 缓冲区等多次拷贝。零拷贝可以减少用户态和内核态之间的数据复制,让数据更直接地从文件系统缓存发送到网络。
2.Kafka 为什么不把消息主要缓存到 JVM 内存?
答:大量使用 JVM 堆内存会带来 GC 压力,消息越多越容易出现停顿。Kafka 依赖操作系统 Page Cache,让 OS 管理缓存,可以减少 JVM GC 对吞吐和延迟的影响。
3.顺序写一定比内存快吗?
答:严格说不一定比内存快。更准确的说法是:磁盘顺序写比磁盘随机写快很多,在某些场景下顺序写磁盘的吞吐可以非常接近内存级别的吞吐。面试时不要绝对化地说"顺序写比内存快"。
4.Page Cache 有什么风险?
答:如果机器宕机,Page Cache 中还没刷盘的数据可能丢失,所以 Kafka 的可靠性还要结合副本机制、ack、刷盘策略等一起看。Kafka 默认更偏吞吐,不是每条消息都同步刷盘。
3. Kafka 的 ack=0、ack=1、ack=-1 分别是什么意思?
Producer 发送消息时,可以通过`acks`参数控制发送可靠性。
| 配置 | 含义 | 可靠性 | 性能 |
| --- | --- | --- | --- |
|`acks=0`| 生产者发送后不等待 broker 响应 | 最低,可能丢消息 | 最高 |
|`acks=1`| Leader 写入成功后返回 ack | 中等,Leader 宕机可能丢消息 | 较高 |
|`acks=-1`/`acks=all`| ISR 中满足条件的副本确认后返回 ack | 最高 | 相对最低 |
`acks=1`是常见默认选择,但如果 Leader 写入成功后还没同步给 follower 就宕机,消息可能丢失。
`acks=all`更可靠,但还需要配合`min.insync.replicas`使用。否则如果 ISR 里只有 Leader 一个副本,`acks=all`也只代表 Leader 写成功,并不能真正保证多副本可靠。
面试回答模板:
>ack=0 是发出去就不管,性能最高但最不可靠;ack=1 是 Leader 写成功就返回,Leader 宕机可能丢;ack=all 是 ISR 中满足条件的副本都确认后才返回,可靠性最高。生产环境如果追求不丢消息,通常使用 acks=all,并配置 min.insync.replicas 大于等于 2。
可能会被追问:
1.`acks=all`是否一定不丢消息?
答:不一定。它还要依赖副本数和`min.insync.replicas`。如果只有一个副本,或者 ISR 中只剩 Leader 一个副本,那么`acks=all`的可靠性也有限。
2.`min.insync.replicas`的作用是什么?
答:它表示写入成功时 ISR 中至少要有多少个同步副本参与确认。比如副本数是 3,`min.insync.replicas=2`,就表示至少要有 2 个同步副本可用,生产者写入才允许成功。
3.如果 ISR 数量不足,Producer 会发生什么?
答:如果配置了`acks=all`,并且 ISR 数量小于`min.insync.replicas`,Producer 写入会失败,通常会收到异常,例如 not enough replicas。
4.`acks=all`会不会导致重复消息?
答:有可能。比如消息已经写入 Leader 和 Follower,但 ack 返回给 Producer 之前 Leader 故障,Producer 以为发送失败并重试,就可能产生重复消息。可以通过生产者幂等性和消费者幂等处理降低影响。
4.acks=all就一定不会丢消息吗?
不一定。
`acks=all`只能说明消息被 ISR 中满足条件的副本确认了,但是否真正高可靠,还取决于副本数和`min.insync.replicas`。
典型问题:
1.如果 topic 只有一个副本,那么`acks=all`也只需要 Leader 自己确认,Leader 宕机后仍可能丢消息。
2.如果`min.insync.replicas=1`,当 ISR 中只剩一个 Leader 时,Producer 仍然可以写入成功,此时可靠性并不高。
3.如果 Leader 写入成功、Follower 同步成功,但 ack 返回给 Producer 之前 Leader 宕机,Producer 可能重试,造成消息重复。
更稳妥的配置:
```properties
acks=all
min.insync.replicas=2
replication.factor=3
enable.idempotence=true
```
面试回答模板:
>acks=all 不等于绝对不丢。它要和多副本、min.insync.replicas 配合才有意义。比如 3 副本、min.insync.replicas=2 时,至少两个同步副本确认后才算成功,这样才能在可靠性和可用性之间取得比较好的平衡。
可能会被追问:
1.为什么副本数通常设置为 3?
答:3 副本可以在可靠性、可用性和成本之间取得比较好的平衡。允许一台 broker 故障后仍有副本可用,同时存储成本不会像 5 副本那样高。
2.`min.insync.replicas=2`时,如果 ISR 只剩 1 个副本会怎样?
答:如果 Producer 使用`acks=all`,写入会失败。这样做是为了避免只有一个副本时继续写入,导致 Leader 宕机后数据丢失风险过高。
3.Kafka 如何处理 Producer 重试带来的重复消息?
答:可以开启生产者幂等性`enable.idempotence=true`。Kafka 会通过 producer id、sequence number 等机制识别同一生产者对同一分区的重复发送,从而避免单分区内由重试造成的重复写入。
5. ISR、OSR、AR 分别是什么?
Kafka 中一个 partition 可以有多个副本。
AR:Assigned Replicas,分区的所有副本。
ISR:In-Sync Replicas,和 Leader 保持同步的副本集合。
OSR:Out-of-Sync Replicas,不在 ISR 中的副本集合。
关系:
```text
AR = ISR + OSR
```
Follower 会不断从 Leader 拉取数据。如果 Follower 落后太多,例如延迟时间或落后消息数超过阈值,就可能被踢出 ISR,进入 OSR。等它重新追上 Leader 后,可以再次加入 ISR。
面试回答模板:
>AR 是所有副本,ISR 是当前和 Leader 保持同步的副本,OSR 是已经落后、被踢出同步集合的副本。Kafka 通过维护 ISR 来判断哪些副本有资格参与高可靠写入和 Leader 选举。
可能会被追问:
1.ISR 是固定的吗?
答:不是。ISR 是动态变化的。Follower 如果落后太多会被踢出 ISR;恢复后重新追上 Leader,又可以加入 ISR。
2.Follower 为什么会被踢出 ISR?
答:通常是因为它从 Leader 同步数据太慢,落后时间或落后数据量超过阈值。可能原因包括 broker 负载高、网络抖动、磁盘慢等。
3.Leader 宕机后为什么通常从 ISR 中选新 Leader?
答:因为 ISR 中的副本与 Leader 同步程度最高,从 ISR 中选 Leader 能最大限度减少数据丢失和不一致。
4.ISR 为空怎么办?
答:要看是否允许 unclean leader election。允许的话可以从非同步副本中选 Leader,但可能丢数据;不允许的话就等待旧 Leader 或同步副本恢复,牺牲可用性。
6. Leader 宕机时,Kafka 如何保证数据一致性?
Leader 宕机后,Kafka 会优先从 ISR 中选举新的 Leader。这样做的原因是 ISR 中的副本和原 Leader 同步程度最高,能最大限度保证数据不丢失。
新 Leader 选出后,其他 Follower 会和新 Leader 对齐数据。对于超过 HW 的日志,Follower 可能会截断,然后从新 Leader 重新同步。
这里有一个关键概念:`HW`,也就是 High Watermark。消费者只能消费到 HW 之前的数据,HW 之后的数据即使已经写入某些副本,也不一定对消费者可见。
面试回答模板:
>Kafka 通过 ISR 和 HW 来保证副本一致性。Leader 故障后优先从 ISR 中选新 Leader,其他副本会截断高于 HW 的日志,再向新 Leader 同步。消费者只能看到 HW 之前的数据,所以可以避免消费到未提交、可能回滚的数据。
可能会被追问:
1.什么是 HW?
答:HW 是 High Watermark,高水位线。消费者只能消费到 HW 之前的消息,HW 之后的消息即使存在于某些副本上,也暂时不可见。
2.什么是 LEO?
答:LEO 是 Log End Offset,表示某个副本日志中下一条待写入消息的 offset,也可以理解为当前日志末尾位置。
3.为什么消费者只能消费到 HW?
答:因为 HW 之前的数据可以认为已经被足够的同步副本确认,相对安全;HW 之后的数据可能只存在于部分副本中,Leader 故障后可能被截断,如果消费者提前读到就会破坏一致性。
4.Leader 自己会截断日志吗?
答:新 Leader 自己通常不会按其他副本截断;其他 Follower 会截断高于 HW 或与新 Leader 不一致的部分,然后向新 Leader 同步。
7. 如果 Leader crash 时 ISR 为空怎么办?
这取决于 Kafka 的`unclean.leader.election.enable`配置。
1.`true`:允许非同步副本成为 Leader。
优点是可用性更高;缺点是新 Leader 数据可能落后,可能造成数据丢失或不一致。
2.`false`:不允许非同步副本成为 Leader。
优点是更重视一致性;缺点是如果没有 ISR 副本可用,就需要等待旧 Leader 恢复,分区会暂时不可用。
面试回答模板:
>如果 ISR 为空,就要看是否允许 unclean leader election。允许的话,可以从非同步副本里选 Leader,提高可用性但可能丢数据;不允许的话,就会等待原 Leader 或 ISR 副本恢复,牺牲可用性保证一致性。
可能会被追问:
1.生产环境一般怎么设置?
答:如果业务强一致、不能接受数据丢失,通常设置为`false`;如果业务更关注可用性,并能接受少量数据丢失或有补偿机制,才可能考虑允许。
2.为什么允许非同步副本成为 Leader 会丢数据?
答:因为非同步副本可能落后于原 Leader,新 Leader 上没有原 Leader 已经写入的部分消息,这些消息就可能丢失。
3.这是 CAP 里的什么取舍?
答:这是可用性和一致性之间的取舍。允许非同步副本选主偏向可用性;不允许则偏向一致性,但分区可能短时间不可用。
8. Kafka 为什么没有做读写分离?
Kafka 通常由 Leader 负责读写,Follower 主要负责从 Leader 同步数据,不像 MySQL 那样常规做读写分离。
主要原因:
1.Kafka 的场景不适合典型读写分离。
Kafka 更关注高吞吐写入和顺序消费,而不是大量随机查询。
2.Follower 数据可能滞后。
Kafka 的副本同步是 Follower 主动从 Leader 拉取,因此 Leader 和 Follower 之间存在短暂不一致窗口。如果允许消费者读 Follower,就要处理读到旧数据、顺序不一致、offset 对齐等问题。
3.会增加一致性复杂度。
Kafka 通过 Leader 统一处理读写,可以让 HW、offset、消费可见性更容易维护。
面试回答模板:
>Kafka 不做典型读写分离,主要是因为它要保证分区内顺序和消费一致性。Follower 和 Leader 之间可能有同步延迟,如果消费者读 Follower,就要面对数据滞后和 offset 不一致问题,所以 Kafka 默认由 Leader 处理读写,Follower 专注同步。
可能会被追问:
1.Kafka 新版本有没有支持从 follower 读?
答:Kafka 后续版本支持了一些面向机架感知和就近读取的能力,但核心语义仍然要围绕 Leader、副本同步和一致性控制来设计。面试中可以回答:传统 Kafka 默认由 Leader 服务读写,Follower 主要负责同步。
2.为什么 MySQL 适合读写分离,而 Kafka 不典型适合?
答:MySQL 常见业务是读多写少,查询请求可以分摊到从库;Kafka 更关注追加写和顺序消费,Follower 读取会引入 offset、顺序和可见性一致性问题。
3.如果跨机房消费,如何减少读取延迟?
答:可以考虑就近部署 Kafka 集群、使用 MirrorMaker 或其他复制工具做跨集群同步,或者结合机架感知能力优化副本和客户端访问路径。
9. Kafka 消费者为什么采用 Pull 模式,而不是 Broker 主动 Push?
Kafka Consumer 采用 Pull 模式,由消费者主动向 broker 拉取数据。
主要原因:
1.消费者可以根据自己的处理能力控制拉取速度。
2.不同消费者性能不同,Pull 模式更容易做背压。
3.如果 broker 主动 Push,可能会把消息推给处理不过来的消费者,导致消费者端堆积、超时甚至崩溃。
4.当 broker 暂时没有数据时,Consumer 可以通过 timeout 机制阻塞等待一段时间再返回。
面试回答模板:
>Pull 模式的好处是消费节奏由消费者自己控制,更适合不同处理能力的消费者。Push 虽然实时性可能更好,但容易把消费者打爆;Kafka 追求高吞吐和稳定性,所以选择 Consumer 主动拉取。
可能会被追问:
1.Pull 模式有没有缺点?
答:有。消费者需要主动轮询,如果参数设置不好,可能出现空轮询浪费资源,或者拉取间隔太长导致实时性下降。
2.如果一直没有消息,Consumer 会不会空轮询?
答:Kafka Consumer 可以通过超时时间和长轮询机制等待数据,不是完全无脑空转。比如 broker 没有足够数据时,可以等待一段时间再返回。
3.Kafka 如何配置单次拉取的数据量?
答:常见参数包括`fetch.min.bytes`、`fetch.max.bytes`、`max.partition.fetch.bytes`、`max.poll.records`等。它们分别影响一次拉取的最小字节数、最大字节数、单分区最大拉取量和一次 poll 返回的最大记录数。
10. Kafka 的 offset 提交方式有哪些?
Kafka offset 提交主要有自动提交和手动提交。
1.自动提交。
Consumer 定期自动提交 offset,使用简单,但不能精确保证消息是否真正处理成功。适合日志采集等对可靠性要求不高的场景。
2.手动同步提交`commitSync`。
会阻塞当前线程,提交失败时会重试。可靠性较高,但性能较差。
3.手动异步提交`commitAsync`。
不阻塞当前线程,性能较好,但默认失败不会自动重试。可以通过 callback 记录提交结果。
在 Spring Kafka 中,`acknowledge`是对手动提交的一层封装,具体行为还要看`ack-mode`配置。
面试回答模板:
>offset 可以自动提交,也可以手动提交。自动提交简单但可能出现消息还没处理完 offset 已经提交的问题。生产中更常用手动提交,处理成功后再提交 offset;同步提交可靠但阻塞,异步提交性能好但要处理失败回调。
可能会被追问:
1.先处理消息再提交 offset,会有什么问题?
答:如果消息处理成功,但提交 offset 前消费者宕机,恢复后会从旧 offset 重新消费,导致重复消费。
2.先提交 offset 再处理消息,会有什么问题?
答:如果 offset 已经提交,但消息处理过程中消费者宕机,这条消息恢复后不会再被消费,可能造成消息丢失。
3.如何做到尽量不丢消息?
答:通常是先处理消息,处理成功后再提交 offset。这样最多产生重复消费,但不容易丢消息。重复消费通过业务幂等解决。
4.如何处理重复消费?
答:可以使用业务唯一键、消息 id、去重表、Redis`setNX`、数据库唯一索引等方式保证幂等。
11. 消费者宕机后,恢复时从哪里继续消费?
消费者恢复后,会根据已提交的 offset 继续消费。
老版本 Kafka 中,offset 可能记录在 ZooKeeper 或本地。新版本默认保存在 Kafka 内置 topic:
```text
__consumer_offsets
```
offset 的 key 通常由三元组确定:
```text
group.id + topic + partition
```
也就是说,同一个消费者组对某个 topic 的某个 partition,会有一个对应的消费进度。
面试回答模板:
>Consumer 宕机恢复后,会从上一次提交的 offset 继续消费。新版本 Kafka 默认把 offset 存在内部 topic`__consumer_offsets`中,按 group.id、topic、partition 这三个维度记录消费进度。
可能会被追问:
1.如果消息处理成功但 offset 没提交,会发生什么?
答:会重复消费。因为 Kafka 认为这个 offset 还没有被消费成功,消费者恢复后会重新拉取。
2.如果 offset 提交成功但消息处理失败,会发生什么?
答:会丢消息。因为 Kafka 认为消费进度已经推进,后续不会再投递这条消息给该消费者组。
3.`__consumer_offsets`默认有多少分区?
答:常见默认值是 50 个分区,具体由`offsets.topic.num.partitions`参数控制。
4.为什么 offset 要按消费者组维度保存?
答:因为不同消费者组之间的消费进度互不影响。同一个 topic 可以被多个消费者组独立消费,每个组都要维护自己的 offset。
12. Kafka 消息堆积了几千万条,已经堆积 10 小时,怎么办?
核心思路:先恢复消费,再临时扩容,加速消化积压,同时评估是否要暂停或降级部分业务。
处理步骤:
1.先定位消费者为什么不消费或消费变慢。
例如消费者异常、下游数据库慢、线程池满、频繁 rebalance、单条消息处理耗时过长。
2.修复 Consumer,让消费恢复正常。
如果业务允许,可以短时间暂停非核心生产者,避免积压继续扩大。
3.判断当前 topic 的 partition 数是否限制了消费并发。
同一个消费者组内,一个 partition 同一时刻只能被一个 consumer 消费。如果 partition 太少,单纯增加 Consumer 数量可能没有效果。
4.临时扩容方案。
如果原 topic 分区数不足,可以创建一个分区更多的临时 topic,写一个分发程序从旧 topic 快速读出,再写入新 topic,然后启动更多消费者并行消费临时 topic。
5.消费完成后恢复正常架构。
堆积处理完后,缩回临时资源,并复盘消费者性能瓶颈和告警阈值。
面试回答模板:
>消息堆积不能只说加机器。要先看瓶颈在哪里,如果是消费者挂了就先恢复;如果是消费能力不足,再看 partition 数是否限制并发。partition 不够时,增加 Consumer 没用,可以建临时多分区 topic 做转储,再用更多 Consumer 并行消费。处理完后再恢复正常资源并做根因复盘。
可能会被追问:
1.为什么增加 Consumer 不一定能提升消费速度?
答:因为同一个消费者组内,一个 partition 同一时间只能分配给一个消费者。如果 topic 只有 10 个 partition,那么同组最多只有 10 个消费者能真正并行消费,更多消费者会空闲。
2.如果不能改变消息顺序,还能这么处理吗?
答:要谨慎。如果业务要求全局有序,临时拆分到多个分区会破坏顺序。通常 Kafka 只能保证单 partition 内有序,如果要保证某个业务维度有序,需要按相同 key 写入同一个 partition。
3.怎么判断是 Kafka 慢还是下游慢?
答:看 consumer lag、消费耗时、poll 频率、下游接口或数据库耗时、消费者线程池状态、broker 磁盘和网络指标。如果 poll 很快但处理慢,通常是下游或业务逻辑慢;如果拉取本身慢,再看 broker、网络和客户端参数。
4.消息积压期间,新消息怎么处理?
答:根据业务优先级决定。可以继续写入原 topic,让消费者按顺序慢慢追;也可以临时暂停非核心生产者;如果新消息优先级更高,可以设计新 topic 或优先级队列,但要注意顺序和一致性影响。
13. Kafka 中 ZooKeeper 起什么作用?
早期 Kafka 对 ZooKeeper 依赖比较重,主要用于存储集群元数据、broker 信息、controller 选举、broker 存活检测等。
旧版本里,消费者消费状态、group 管理、offset 也可能放在 ZooKeeper 中。后来 Kafka 引入新的 consumer group 协调机制,offset 默认保存在 Kafka 内部 topic`__consumer_offsets`中,减少了对 ZooKeeper 的依赖。
需要注意:新版本 Kafka 已经逐步引入 KRaft 模式,用 Kafka 自己的元数据管理机制替代 ZooKeeper。面试时如果被问"ZooKeeper 在 Kafka 里的作用",可以先回答传统架构,再补一句新版本趋势。
面试回答模板:
>传统 Kafka 中 ZooKeeper 主要负责元数据管理、controller 选举和 broker 存活检测。早期 consumer offset 也可能存在 ZooKeeper 中,后来新版 consumer 使用 Kafka 内部的 group coordination 协议,offset 默认保存在`__consumer_offsets`,对 ZooKeeper 的依赖逐渐减少,新版本还引入 KRaft 模式替代 ZooKeeper。
可能会被追问:
1.offset 现在默认存在哪里?
答:默认保存在 Kafka 内部 topic`__consumer_offsets`中,见第 11 题。
2.controller 是干什么的?
答:controller 负责分区 Leader 选举、分区副本状态变化、broker 上下线处理等集群管理工作。
3.KRaft 是什么?
答:KRaft 是 Kafka 自己的元数据仲裁机制,用来替代 ZooKeeper,让 Kafka 集群不再依赖外部 ZooKeeper 管理元数据。
14. Producer 发送消息是异步的,怎么知道是否发送异常?
Producer 异步发送消息时,可以注册 callback 回调函数。Broker 返回 ack 后,Producer 会触发回调。
回调通常有两个核心信息:
1.`RecordMetadata`:消息发送成功后的元数据,比如 topic、partition、offset。
2.`Exception`:发送异常信息。如果`Exception == null`,说明消息发送成功;否则说明发送失败。
生产中不能只调用`send()`就不管结果,至少要在回调里记录异常,必要时做重试、告警或写入补偿表。
面试回答模板:
>Kafka Producer 异步发送可以通过 callback 感知结果。回调里有`RecordMetadata`和`Exception`,如果异常为空说明发送成功,否则说明发送失败。生产环境一般会在 callback 里记录日志、告警或做补偿处理。
可能会被追问:
1.Producer 发送失败后能不能无限重试?
答:不建议无限重试。重试会增加延迟,也可能造成消息重复。要结合`retries`、`delivery.timeout.ms`、幂等性和业务补偿设计。
2.Producer 重试会不会造成乱序?
答:可能。尤其是同一分区内多个请求并发发送时,前一个请求失败重试,后一个请求先成功,就可能乱序。开启幂等性并合理配置`max.in.flight.requests.per.connection`可以降低风险。
15. Kafka Producer 如何优化写入速度?
Producer 写入速度通常从批量、压缩、分区并行和可靠性参数几个方向优化。
常见手段:
1.增大`batch.size`。
让 Producer 尽量批量发送,减少网络请求次数,提高吞吐。
2.适当增大`linger.ms`。
让 Producer 多等一小段时间凑批次,吞吐会更好,但延迟会增加。
3.开启压缩。
比如`compression.type=snappy`、`lz4`、`zstd`,可以减少网络传输和磁盘占用。
4.增加 partition 数。
分区更多时,Producer 可以并行写入不同分区,提高整体吞吐。
5.合理设置 ack。
`acks=0/1`性能更高但可靠性较弱;`acks=all`可靠性更强但延迟更高。
6.如果`acks=all`下延迟变大,可以适当增加 follower 同步线程。
例如调大`num.replica.fetchers`,让 follower 更快从 Leader 拉取数据。
面试回答模板:
>Producer 优化写入速度主要看批量、压缩和并行。可以增大`batch.size`、适当调大`linger.ms`、开启压缩、增加 topic partition 数。如果可靠性要求高用了`acks=all`,还要关注副本同步速度,比如 follower 拉取线程、broker 磁盘和网络瓶颈。
可能会被追问:
1.`batch.size`越大越好吗?
答:不是。太大会增加内存占用和等待时间,如果流量不够也凑不满批次,收益有限。
2.`linger.ms`会带来什么副作用?
答:它会增加消息等待时间,吞吐提升但延迟变大,适合吞吐优先场景。
3.增加 partition 一定能提升性能吗?
答:不一定。partition 更多会增加文件句柄、内存、leader 选举和客户端管理成本,见第 23 题。
16. 指定一个 offset,Kafka 怎么查找到对应消息?

Kafka 通过 partition、segment 和稀疏索引定位消息。
查找过程:
1.一个 topic 会拆成多个 partition,每个 partition 是一个有序日志。
2.每个 partition 又会拆成多个 segment 文件,常见文件包括`.log`、`.index`、`.timeindex`。
3.segment 文件名通常是该 segment 第一条消息的 base offset。
4.Kafka 先根据目标 offset 找到对应 segment。
5.再通过`.index`稀疏索引找到不大于目标 offset 的最近索引项。
6.索引项里有相对 offset 和物理位置,再去`.log`文件中从该位置开始顺序扫描,找到目标消息。
索引为什么是稀疏的?
1.如果每条消息都建索引,索引文件会非常大。
2.稀疏索引能减少内存和磁盘占用。
3.缺点是命中索引后,还需要在小范围内顺序扫描。
面试回答模板:
>Kafka 查 offset 不是全量扫描,而是先根据 offset 找到对应 segment,再查 segment 的稀疏 index。index 里记录相对 offset 和 log 文件物理位置,Kafka 找到最近索引后再去 log 文件中顺序扫描一小段,最终定位消息。
可能会被追问:
1.Kafka 为什么要把 partition 拆成多个 segment?
答:方便删除过期数据、控制单个文件大小、提升索引和日志管理效率。
2.`.index`文件为什么不用全量索引?
答:全量索引太占空间,稀疏索引能在查询效率和存储成本之间平衡。
3.partition 内消息为什么有序?
答:同一个 partition 是追加写日志,消息按 offset 递增,见第 17 题。
上篇先把 Kafka 面试最容易被问到的基础和原理题梳理完了。
如果已经能把这些题说顺,下一篇就可以继续看更容易拉开差距的内容:顺序消费、重复消费、rebalance、事务、延迟队列、日志清理、生产环境 partition 选择和参数调优。