5月27日 22:10

Kafka 消息丢失的原因有哪些?怎么解决?

答案概览

Kafka 消息丢失发生在三个环节:Producer 发送端Broker 存储端Consumer 消费端。核心对策:Producer 配 acks=all + 重试,Broker 配多副本 + 禁脏选举,Consumer 关自动提交改手动确认。

Producer 端:消息发出去就丢了?

丢失原因:

  • acks=0acks=1,Leader 写入成功就返回,Follower 还没同步 Leader 就挂了
  • 异步发送不带回调,发送失败无感知
  • retries 未配置,网络抖动直接丢消息

解决方案:

properties
acks=all retries=3 enable.idempotence=true max.in.flight.requests.per.connection=5

acks=all 要求所有 ISR 副本确认写入才算成功。enable.idempotence=true 开启幂等生产者,防止重试导致消息重复。注意:开启幂等性时 max.in.flight.requests.per.connection 需小于等于 5,否则幂等性失效。

producer.send(record, callback) 代替 producer.send(record),在回调里处理失败逻辑。

Broker 端:写进去了但读不到了?

丢失原因:

  • 副本数只有 1,Broker 宕机直接丢数据
  • Leader 崩溃后,未同步完的 Follower 被选为新 Leader(脏选举),未同步消息丢失
  • 异步刷盘,数据还在 PageCache 没落盘就宕机

解决方案:

properties
default.replication.factor=3 min.insync.replicas=2 unclean.leader.election.enable=false

replication.factor=3 保证三副本冗余。min.insync.replicas=2 要求至少 2 个副本在 ISR 中,否则 Producer 写入报错——宁可不可用也不丢数据。unclean.leader.election.enable=false 禁止落后副本参与选举,这是防丢的关键开关。

Consumer 端:消费了但白消费了?

丢失原因:

  • enable.auto.commit=true,消息拉取后自动提交 offset,但业务还没处理完就挂了,重启后这条消息不会再投递
  • 多线程消费时,处理慢的线程还没完成,offset 已被其他线程推进

解决方案:

properties
enable.auto.commit=false

关闭自动提交,业务处理完成后手动调用 consumer.commitSync()。多线程场景下,每个线程维护自己的 offset,处理完再提交。

消费者还需实现幂等性:同一条消息可能被重复投递(rebalance 后),用唯一标识去重。

追问:acks=all 就一定不丢消息吗?

不一定。如果 ISR 中只剩 Leader 自己,acks=all 退化为 acks=1。所以 min.insync.replicas=2 必须配合使用——当 ISR 不足时拒绝写入,用可用性换可靠性。

配置速查

环节关键配置推荐值
Produceracksall
Producerretries≥3
Producerenable.idempotencetrue
Brokerreplication.factor3
Brokermin.insync.replicas2
Brokerunclean.leader.election.enablefalse
Consumerenable.auto.commitfalse
标签:Kafka