Kafka 常被概括成“高吞吐消息队列”,但真正排查问题时,光知道高吞吐不够。生产端的 acks、副本同步里的 ISR、消费端的 offset 提交,都会直接影响可靠性和重复消费。
这篇先抓几个最常用的点,适合做 Kafka 排障和面试复盘的基础框架。
ISR 是什么
Kafka 一个分区会有 leader 副本和 follower 副本。生产者写入时,通常写到 leader。follower 会从 leader 拉取数据,保持同步。
ISR 可以理解为“当前跟得上的副本集合”。一个副本要留在 ISR 里,通常要满足两类条件:
- broker 还活着,能和集群元数据服务保持连接。
- follower 同步 leader 的数据没有落后太多。
如果 follower 长时间跟不上,就会被踢出 ISR。等它追上以后,才可能重新加入。
ISR 的意义是:Kafka 在判断消息是否足够可靠时,不是看所有副本,而是看当前同步状态正常的一组副本。
acks 决定生产端等到什么时候算成功
生产者发送消息时,acks 决定“服务端确认到什么程度,客户端才认为发送成功”。
常见取值有三个:
acks=0:生产者发出去就不等确认。吞吐最好,但可靠性最低。网络抖动、leader 异常时,客户端可能不知道消息丢了。
acks=1:leader 写入成功就返回确认。比 0 可靠,但如果 leader 刚确认就挂了,而 follower 还没同步到这条消息,仍然可能丢。
acks=all 或 acks=-1:leader 等 ISR 中符合条件的副本确认后再返回。可靠性更高,但延迟和吞吐会受影响。
所以 acks 不是越大越好,而是要和业务场景匹配。日志、埋点可以更偏吞吐;订单、支付、状态变更则更重可靠性。
Kafka 为什么能扛高并发
Kafka 高吞吐不是单靠“写得快”,而是多种设计叠加:
- 分区让主题可以横向扩展。
- 顺序写磁盘,减少随机 IO。
- 依赖操作系统页缓存,而不是把大量数据都塞进 JVM 堆。
- 批量发送和批量拉取降低网络开销。
- 零拷贝减少数据在内核态和用户态之间的搬运。
- 端到端压缩降低网络传输体积。
这也解释了为什么分区数、批量大小、压缩方式、磁盘和网络都会影响 Kafka 性能。只盯着 JVM 参数通常不够。
消费位点提交决定失败后怎么恢复
消费者读消息时,Kafka 需要知道这个 consumer group 消费到了哪里。这个位置就是 offset。
如果开启自动提交,消费者会定期提交 offset。它简单省事,但有一个风险:业务逻辑还没处理成功,offset 已经提交了。进程这时挂掉,重启后可能跳过那条消息。
如果手动提交,可以在业务处理成功后再提交 offset。这样更安全,但要自己处理重复消费、异常重试和提交失败。
比较稳的思路是:
- 先拉消息。
- 执行业务处理。
- 业务成功后提交 offset。
- 业务失败时不要提交,进入重试或死信流程。
这样做仍然可能重复消费,因为提交成功前进程挂掉,消息会被再次拉取。所以消费端业务最好做幂等。
自动提交不是绝对不能用
自动提交适合对丢失和重复不敏感的场景,比如部分日志、监控采样、临时统计。它可以减少代码复杂度。
但只要消费逻辑有副作用,比如写数据库、调外部接口、发通知、扣库存,就不要只依赖自动提交。至少要想清楚:
- 处理失败是否允许丢弃。
- 重复处理会不会造成脏数据。
- 是否有业务幂等键。
- 是否需要重试队列或死信队列。
- offset 提交和业务写入是否存在先后风险。
消息队列的可靠性不是只看 broker,消费端的处理模型同样重要。
排障时可以按这条线看
遇到 Kafka 消息丢失、延迟或重复消费,可以先按顺序问:
- 生产端
acks是多少。 - topic 副本数和最小 ISR 配置是否合理。
- ISR 是否频繁收缩。
- broker 磁盘、网络、GC 是否异常。
- 消费端是自动提交还是手动提交。
- 业务处理是否幂等。
- 是否有重试和死信链路。
Kafka 的难点不是会不会发消息,而是能不能解释“为什么这条消息现在是成功、丢失、延迟还是重复”。把 ISR、acks 和 offset 串起来,排查就会清楚很多。



