在使用 Kafka 时,消息丢失、重复消费和消息积压是比较常见的问题。下面我们来分别介绍对应的处理方法。
一、消息丢失
消息丢失通常发生在生产者发送、Broker 存储和消费者提交进度这三个环节。
1. 生产者发送确认
生产者发送消息时,可以将 acks 设置为 all,让 Kafka 等待所有同步副本确认后再返回成功结果。
acks=all
同时开启生产者幂等性,并配置合理的重试次数:
enable.idempotence=true retries=3
这样可以降低网络异常导致消息发送失败或重复写入的风险。
2. 设置消息副本
Topic 应设置多个副本,使消息分布在不同 Broker 上。例如:
replication.factor=3
同时设置最小同步副本数:
min.insync.replicas=2
当可用副本数量不足时,Kafka 会拒绝继续写入,从而避免消息只保存在单个节点上。
3. 合理提交 Offset
消费者应在业务处理完成后再提交 Offset。否则,消息还没处理成功,Offset 却已经提交,程序重启后就可能直接跳过这条消息。
可以关闭自动提交:
enable.auto.commit=false
处理成功后,再手动提交消费进度。
二、重复消费
重复消费一般是因为消费者处理完消息后,还没有提交 Offset 就发生了宕机。消费者重新启动后,会再次读取之前的消息。
Kafka 很难完全避免这种情况,因此通常需要从业务层保证幂等性。
1. 使用唯一业务编号
可以使用订单号、流水号等作为唯一标识。消费者处理消息前,先判断该编号是否已经处理过:
如果消息已经处理:直接跳过
如果消息未处理:执行操作并记录处理结果
2. 数据库设置唯一约束
例如使用订单号作为唯一键,即使同一条消息被执行两次,第二次操作也不会产生重复数据。
3. 处理成功后再提交 Offset
消费者应按照以下顺序执行:
拉取消息 → 执行业务处理 → 处理成功 → 提交 Offset
如果业务处理失败,可以暂不提交 Offset,等待后续重新消费。
三、消息积压
消息积压是指生产者写入消息的速度超过消费者处理消息的速度。
1. 增加消费者数量
在同一个 Consumer Group 中增加消费者,可以提高消息处理的并行度。
但是,消费者数量不能超过 Partition 数量。假设 Topic 只有三个 Partition,那么同一个消费者组最多同时有三个消费者真正处理消息。
2. 增加 Partition
如果现有 Partition 数量不足,可以增加 Topic 的 Partition,使更多消费者能够并行消费。
Partition 越多
↓
可分配的消费者越多
↓
并行处理能力越强
3. 优化消费者处理速度
应检查消费者是否存在以下问题:
-
单条消息处理时间过长;
-
数据库或其他下游服务响应缓慢;
-
每次拉取的消息数量过少;
-
消费者频繁发生异常或重平衡。
可以通过批量拉取、批量写入和优化业务代码来提高消费速度。
4. 监控消费延迟
Kafka 可以通过 Consumer Lag 判断消息是否积压。Lag 持续增大,说明消费者处理速度不足,需要及时扩容或优化。
四、总结
Kafka 解决这三个问题的思路可以概括为:
-
消息丢失:发送时确认、Broker 保存副本、处理成功后提交 Offset;
-
重复消费:使用手动提交,并通过唯一编号和幂等逻辑避免重复处理;
-
消息积压:增加 Partition 和消费者数量,同时优化消费业务。