一、Kafka 无消息丢失核心概念
Kafka 只对“已提交”的消息做有限度的持久化保证。
二、生产者程序丢失数据
目前Kafka Producer 是异步发送消息,也就是说如果你调用的是 producer.send(msg)这个API,那么它通常会立即返回,但此时你不能认为已经发送成功了。 如果出现消息丢失,我们是无法知晓的, 这种发送方式不靠谱,不过还有一些公司在用这种API发送消息。
这种发送方式,哪些因素会导致发送不成功呢 ?例如:网络抖动导致消息根本没有发送到broker端;或者消息本身被Broker拒绝(消息格式有误,消息太大)。
Kafka 社区提供了解决方案: Producer 要使用待回调通知的发送API,也就是是用哦个 producer。send(msg,callback),在callback 回调中, 能准确的告诉你消息是否提交成功,如果提交失败,可以进行重试、整改、监控等 措施。
三、消费者丢失数据
Consumer端丢失数据主要体现在Consumer 要消费的消息不见了。 Consumer程序有一个“位移”的概念,表示这个Consumer 当前消费到Topic 分区的位置。下图表示Consumer 端的位移数据
在上图中 Consumer A 当前位移值是 9 ; Consumer B 的位移值是11;
Consumer端丢失数据 一般有两种情况:
1.) Consumer poll 数据时先更新位移,再阅读消息, 这样可能出现 位移已经更新,但数据未读取到。
解决方案:先消费消息,再更新 位移。
2 ) Consumer 获取到消息后开启多线程异步处理消息,消息未处理完成,而Consumer
自动提交位移。假如某个线程运行失败,负责的消息没有被成功处理,但位移已经更新,因此就出现了消息丢失。 解决方案:如果多线程异步消费消息,Consumer程序不要开启自动提交位移,而是要应用程序手动提交位移。
四、最佳实践
1) Producer 不要使用 producer.send(msg),而是使用 producer.send(msg,callback) 。一定需要处理 callback的成功或失败逻辑;
2)设置acks=all。acks 是Producer 的一个参数, 代表所有broker 副本 都接收到消息,该消息才算“已提交”;
3)设置retries 为一个较大值。retries 是Producer 的一个参数,表示重试次数,如果非网络出现抖动,消息发送失败后可以自动重试;
4)设置unclean。leader。election。enable = false。这是Broker的参数,它控制这哪些Broker 有资格竞选分区的leader。如果一个Broker 落后原先的Leader 太多,那么它一旦被选为新的Leader ,必然造成消息丢失。顾设置为false 防止这种情况出现;
5)设置replication.factor >=3 。这是Broker 端参数,这个参数表示将消息保存多份,目前防止消息丢失的主要机制就是冗余;
6)设置min.insync.replicas > 1 。这是Broker端参数,控制的是消息至少被写入到多少个副本才算“已提交”。设置成大于1可以提升消息持久性。在实际环境中千万不要使用默认值1。
7)确保 replication.factor >min.insync.replicas 。如果两个值相等,那么只要有一个副本挂机,整个分区就无法正常工作了。我们不仅要改善消息的持久性,防止数据丢失,还要在不降低可用性的基础上完成。推荐设置replication.factor =min.insync.replicas+1。
8)确保消息消费完成在提交。Consumer 端有个参数 enable.auto.commit,最好把它设置成false,并采用手动提交位移的方式。