在kafka中,消息丢失的场景有很多,但是并不是每一种场景都能被称为消息丢失,kafka中消息的丢失是有条件的。这里条件主要分为两个:
1、已经提交的消息丢失。
2、被持久化的消息的丢失。
如果不属于这两种情况的,那么严格来说就不属于消息丢失。
消息丢失定义
已提交消息丢失
已提交的定义,就是对于发送者来说,producer发送一条消息后,收到一个或者多个broker的ack后,那么这个消息才算是已提交。对于已提交的消息,如果存在丢失的现象,才能被称为消息丢失。至于收到多少个ack,算是已经确认,这个是由发送者端一个配置参数来决定的,对于该参数的描述,后面在进行说明。
已持久化消息丢失
持久化消息丢失是说,即使消息已经持久化在了broker中,但是我们却无法保证broker不会出现问题,如果保存消息的broker都出现了问题,那么消息的丢失也是在所难免的了。为了降低broker宕机带来的消息丢失,可以适当提高分区副本个数。设置 replication.factor = n,设置分区副本个数为n,尽量保持n尽量大一些。因为目前防止消息丢失的主要机制就是冗余。
消息丢失的场景
发送者端消息丢失
目前producer消息发送都是异步的,也就是说,你调用了send(msg)这个方法发送消息,方法会立即返回,但是此时却不能保证消息已经发送成功,这个被发送的消息也不能被称为已提交消息。
如果使用这种方式发送消息,导致消息发送不成功的因素还是有很多:
1.网络抖动,消息压根就没有发送到broker中。
2.发送的消息格式有问题,broker拒收。
3.broker宕机,消息发送不出去
这三种情况,broker并没有收到消息,消息也不能被称为已提交的消息,所以,以上原因导致的消息丢失,不能被称为kafka的消息丢失。
对于发送者端消息丢失,可以通过调整发送者发送消息的方式进行优化。
使用send(msg)的消息发送的方式是异步的,消息发送的状态对于producer来说是不可见的,对于消息是否成功发送到broker中,producer也是不知道的。为了让producer可以感知,消息发送的的状态信息,kafka提供了带有回调通知的发送api:producer.send(msg,callback)
其中回调函数callback可以告诉生产者消息是否真的提交成功了,当消息发送成功,onSuccess方法会被调用,当消息发送失败,onFailure方法会被调用,这个时候,就可以在onFailure中对发送失败的消息进行针对性的处理,比如对消息发送进行重试。
消费者端消息丢失
consumer端消息丢失数据主要体现在Consumer消费的消息找不到了。这里要说一下Consumer端的"位移"的概念,它记录了消费者从一个分区的哪个位置开始消费数据。如下图:
上图中ConsumerA在分区A中消费的位移是6,ConsumerB在分区A中消费的位移是7。这就表明,ConsumerA下一次消费的数据从位移为6的位置开始,ConsumerB下一次消费数据从位移7开始。
这个位移和我们看书时的书签很类似,它记录了我们当前读了多少页,下次读书的时候,直接跳到书签记录的位置继续阅读即可。可以避免重复阅读和阅读遗漏。
不过在我们读书的过程中使用书签主要分为2步:第一步是读书,第二步是及时更新书签位置。如果先读书,后更新书签位置的流程的话,当读完书忘记更新书签,下次读书的时,可能会从之前的书签处开始,导致消息重复消费。如果按照先更新书签,再读书的流程的话,更新完书签,由于临时有事中止了阅读,下次直接从最新书签开始阅读的话,那么就导致部分内容没有阅读,也就导致了消息的丢失。
相比消息重复,消息丢失的问题更为严重。所以为了避免消费端消息丢失,在消息消费的过程中,应该先处理消息,消息处理成功后,再更新消费位移。
避免消息丢失的参数配置
1、设置 acks = all。acks 是 Producer 的一个参数,代表了你对“已提交”消息的定义。如果设置成 all,则表明所有副本 Broker 都要接收到消息,该消息才算是“已提交”。这是最高等级的“已提交”定义。
2、设置 retries 为一个较大的值。这里的 retries 同样是 Producer 的参数,对应前面提到的 Producer 自动重试。当出现网络的瞬时抖动时,消息发送可能会失败,此时配置了 retries > 0 的 Producer 能够自动重试消息发送,避免消息丢失。
3、设置 unclean.leader.election.enable = false。这是 Broker 端的参数,它控制的是哪些 Broker 有资格竞选分区的 Leader。如果一个 Broker 落后原先的 Leader 太多,那么它一旦成为新的 Leader,必然会造成消息的丢失。故一般都要将该参数设置成 false,即不允许这种情况的发生。