精选·Kafka与消息队列

Kafka 的 acks 机制是什么?怎么配置才能保证数据不丢失?

91学AI·2026/7/13·9 阅读

考察点

这题表面问一个参数,实际考你对整条数据链路的可靠性有没有系统认识。只想背"acks=all"的人会在追问里露馅:min.insync.replicas 是什么?Broker 落盘了吗?消费端位移提交时机对不对?面试官想看到你能把"不丢"拆成生产、Broker、消费三段分别给方案,并且知道每段的代价。

参考答案

acks 三档语义

acks 是 Producer 端参数,决定"一条消息算发送成功"需要多少个副本确认:

取值语义吞吐风险
0发出去就不管,不等任何确认最高Leader 挂了消息直接丢,发送方无感知
1等 Leader 写入本地日志就返回Leader 写完、Follower 还没同步时 Leader 宕机,这条消息丢
all(-1)等 ISR 全部副本确认较低ISR 收缩到只剩 Leader 时退化为 acks=1

acks=1 的丢数据场景要讲清楚:Leader 落盘返回成功,Follower 还没拉走这条消息,此时 Leader 宕机,某个 Follower 当选新 Leader,那条消息就没了。Producer 侧看到的明明是"发送成功",这就是很多人误以为自己配了 acks=1 就安全的地方。

acks=all 也有坑:如果 ISR 只剩 Leader 一个(其他 Follower 全被踢出去了),all 实际只等 Leader。所以必须搭配 Broker 端的 min.insync.replicas=2,意思是 ISR 不足 2 个副本时,Broker 直接拒绝写入,Producer 收到 NotEnoughReplicas 异常。宁可写不进去报错,也不静默降级成单副本写入——这是用可用性换可靠性的经典取舍,副本数至少配 3 才有意义。

生产端不丢的完整姿势

最小配置组合是:

  • acks=all
  • Broker 侧 min.insync.replicas=2,Topic 副本数 replication.factor=3
  • retries 调大(新版本默认 Integer.MAX_VALUE),enable.idempotence=true(新默认开启),避免重试导致乱序或重复
  • delivery.timeout.ms 控制整体超时,别让重试无上限地占着发送配额

代码层面,send() 返回的是 Future,异步发送必须处理回调里的异常;同步 send().get() 才能拿到最终确认。只调 send 不看结果,等于 acks 白配。

还有一个常被忽略的点:max.in.flight.requests.per.connection。不开幂等时,如果它大于 1 且发生重试,可能出现消息乱序——第一批失败重试,第二批先成功了。开幂等后这个值可以放到 5,Kafka 用序列号保证顺序。

Broker 端:写进 page cache 不等于落盘

ISR 确认只保证消息到了多个副本的内存(page cache),不保证刷盘。flush.messagesflush.ms 这两个参数官方都不建议配,因为 Kafka 的设计哲学是:靠多副本冗余扛单机宕机,而不是靠单机刷盘扛断电。真要扛机房级断电,那是跨机房容灾的话题,不是 flush 参数能解决的。副本数够、ISR 健康,单点宕机丢不了数据,这个信任链条要说出来。

另外要监控 ISR 的抖动:如果某个分区的 ISR 频繁伸缩(Broker 端有对应的 UnderReplicatedPartitions 和 ISR shrink/expand 指标),说明 Follower 在反复掉队,此刻即使 acks=all,实际参与确认的副本数可能经常贴着 min.insync.replicas 的下限走,可靠性水位比配置看上去要低,这种情况该去查慢盘或网络,而不是继续加参数。

消费端:不丢的最后一段

Producer 和 Broker 配得再好,消费端位移提交错了照样"丢"——消息还没处理完,offset 先提交了,Consumer 崩溃重启后从已提交的位移继续,那条消息就被跳过了。正确姿势是处理完再提交位移,自动提交(enable.auto.commit=true)在消费慢、处理链路长的场景就是定时炸弹,改手动提交,或者用事务/原子写把"处理结果"和"位移"绑在一起。

一句话收拢:不丢 = 生产端 acks=all + 幂等重试,Broker 端 3 副本 + min.insync.replicas=2,消费端先处理后提交。三段缺一段,"不丢"都不成立。

可能的追问

  • acks=all + min.insync.replicas=2 就一定能扛住吗?什么场景还丢? ISR 里两个副本所在机器同时挂、或者开了 unclean leader election 时仍可能丢;另外配置了 retention 的消息被清理属于"正常过期",不算丢但业务上要想清楚。
  • acks=all 吞吐掉多少,怎么补回来? 等待副本确认会增加单条延迟,靠 Producer 的 batching(linger.ms + batch.size)和多分区并行把吞吐补回来,延迟敏感的分区可以单独评估。
  • 为什么 retries 要配合幂等? 单纯重试在网络抖动时可能让同一条消息被写入两次(Broker 已写入但 ACK 丢了),幂等生产者用 PID+序列号去重,重试才真正安全。

评论 (0)

暂无评论,快来抢沙发吧!

91学AI

© 2026 91学AI · 按岗位学 AI 与大数据. All rights reserved.