题目:Kafka 如何保证消息不丢失?
难度:medium
标签:db/mq/kafka, mq/kafka, general/knowledge, difficulty/medium
评分:⭐⭐⭐☆☆(3/5)
Kafka 保持保证消息不丢失,要确保消息不丢失,首先要从三个端去考虑。首先是生产者,生产者端发送消息的时候,要明确能发到 Broker 管理端,也就是说这条消息发送出去,要通过管理端 Broker 的确认,确认告知这条消息已经发出了,才能确认这条消息发出了生产者端。然后其次到 Broker Broker 的时候进行落盘,把这条消息落到磁盘中,明确确保这条消息落在本地,通过持久化顺序写,保证消息的消息确认保存下来,确保这个消息已经不会再丢失,持久化的落到本地。第三在消费者端,消费者消费这条消息的时候,明确的告知生 Broker 这条消息我消费了,并且消费成功了,确保整个消息链路每个节点都知道自己的结果,最终实现整个消息不丢失。然后对应的在消费者上应该会有重试,如果消费出现问题可以重试,然后生产者如果出现问题要重发,大概是这么个机制。
优点:
不足:
acks=all、retries、enable.idempotence=true(幂等)replication.factor、min.insync.replicas、unclean.leader.election.enable=falseenable.auto.commit=false(手动提交)、"业务处理完再 commit"的正确顺序补充(必须掌握的关键参数):
Producer 端:
acks=all:等待所有 ISR 副本确认retries=Integer.MAX_VALUE:无限重试enable.idempotence=true:开启幂等,Producer 重启不重复max.in.flight.requests.per.connection=5:幂等允许的最大值Broker 端:
replication.factor=3:3 副本min.insync.replicas=2:至少 2 副本确认unclean.leader.election.enable=false:不允许非 ISR 副本当选 Leaderlog.flush.interval.messages / log.flush.interval.ms:刷盘策略(一般依赖 OS Page Cache,不建议强制刷盘)Consumer 端:
enable.auto.commit=false:关闭自动提交commitSync核心考点定位:考察是否能分层次、带参数地回答 Kafka 消息可靠性,涉及"至少一次"和"精确一次"两个语义层级。
知识点拆解:
transactional.id + isolation.level=read_committed)acks=all:等待所有 ISR 副本确认才返回retries=MAX:网络异常自动重试enable.idempotence=true:Producer 崩溃重启后不会重复发送(依赖 transactional.id 生成 PID)max.in.flight.requests.per.connection=5:幂等允许的最大值,否则乱序replication.factor=3:至少 3 副本min.insync.replicas=2:至少 2 副本确认才返回unclean.leader.election.enable=false:不选非 ISR 副本当 Leaderenable.auto.commit=false:关闭自动提交commitSync:防止处理失败但 offset 已提交enable.idempotence=true)replication.factor + min.insync.replicas)transactional.id + read_committed)核心权衡:可靠性 vs 性能。ack=all + min.insync=2 + idempotence 会带来明显延迟,生产上需按业务分级。
考察方向:
enable.idempotence 的 PID 机制、max.in.flight=5 与乱序的关系、Consumer 事务如何与外部存储配合延伸递进面试题:
acks=all 但 ISR 只剩 1 个副本,会怎样?request.timeout.ms,业务侧报错;需要监控 ISR 收缩告警面试官您好,Kafka 保证消息不丢失需要按 Producer、Broker、Consumer 三段链路来设计,每一段都有对应的关键配置。
Producer 端有 4 个关键点:第一 acks=all,让 Producer 等所有 ISR 副本确认才返回;第二 retries 设置为最大,网络异常自动重试;第三 enable.idempotence=true 开启幂等,防止 Producer 崩溃重启后重复发送,这是靠 transactional.id 生成 PID 实现的;第四 max.in.flight.requests.per.connection=5,幂等允许的最大值,超过会乱序。
Broker 端主要是副本配置:replication.factor=3 保证 3 副本,min.insync.replicas=2 保证至少 2 副本确认才返回成功,unclean.leader.election.enable=false 不允许非 ISR 副本当 Leader,避免数据丢失。刷盘策略一般依赖 OS Page Cache,不主动 fsync。
Consumer 端最关键的是 enable.auto.commit=false 关闭自动提交,业务处理成功后再手动 commitSync,防止处理失败但 offset 已经提交的场景。同时消费端要做幂等——数据库唯一索引、Redis 记录、去重表都可以。
需要澄清一个概念:Kafka 只能保证至少一次,不能保证精确一次。要实现端到端 Exactly-Once,需要 Producer 幂等 + Broker 副本可靠 + Consumer 事务配合(transactional.id + isolation.level=read_committed),并且外部存储也要用事务或唯一约束配合。
生产上一般按业务分级:重要业务用严格配置(acks=all + min.insync=2 + idempotence),普通业务可以适当放宽以换取性能。同时要监控 ISR 收缩告警,防止 ISR 只剩 1 个副本时 Producer 阻塞。