文章目录

  • 前言
  • 消息丢失的场景
  • 1. 生产消息时丢失
  • 2. ACK配置
  • 3. min.insync.replicas
  • 4. 消息的提交
  • 5. unclean.leader.election.enable
  • 6. replication.factor
  • 总结


前言

我们知道Kafka对于消息的可靠性可以做到至少一次(at least once)的保证,即消息不会丢失,但有可能重复发送,本文就来分析一下Kafka究竟是如何做到的。

消息丢失的场景

要确保消费不丢失,当然就需要先搞清楚在什么样的情况下消费会丢失?

1. 生产消息时丢失

我们知道Kafka在发送消息时是异步的,所以如果发送时调用的是Future<RecordMetadata> send(ProducerRecord<K, V> record);方法,那么很可能成功返回了,但消息实际上并没有发送成功。

那么针对这样的问题,建议你使用Future<RecordMetadata> send(ProducerRecord<K, V> record, Callback callback);带回调的方法,根据最终的回调结果来判断消息是否最终写入成功,当然如果生产者一直未收到Broker应答,则会通过重试的方式来保证消息可靠性,重试的次数由参数retries来控制,默认值为Integer.MAX_VALUE

2. ACK配置

生产者在确认请求完成之前要求leader已收到的确认数,可以定义为这是对消息发送成功的定义。

这个参数一共有3个值,分别是0,1,all,默认为1。

0:生产者只要把消息发送出去即可,不用等待broker的处理结果,消息将立即添加到socket buffer并被视为已发送。在这种情况下,无法保证服务器已收到消息,并且retries配置将不会生效(因为客户端通常不会知道任何故障)。为每条消息返回的偏移量将始终设置为-1。
设置为0,吞吐量最高,同样消息的丢失率也最高。

1:生成者需要等分区leader将消息写入成功后才认为此消息发送成功,兼顾了吞吐量和消息丢失的问题,但是同样有消息丢失的风险,比如当leader写入成功后突然挂了,其他分区跟随者并为能够将此消息同步,则此消息丢失。

all:生产者会等待所有的副本都写入成功后才认为此消息发送成功,只要至少有一个同步副本保持活跃状态,消息就不会丢失,这是最安全的保障,是吞吐量最低的。

3. min.insync.replicas

这个参数定义了消息至少要被写入多少个副本才算是“已提交”,默认是1,建议设置成大于1,假设一共有3个副本,当ack设置为all时,需要3个副本都写入成功,才算消息发送成功,此时min.insync.replicas设置如果设置成小于3,实则就不无用,如果设置大于3,则永远无法满足其要求。

4. 消息的提交

如果你设置为自动提交消息,则很有可能因为处理不当,导致消息还没有被真正的消费,就已经被提交offset,所以最保险的方式是设置为手动提交,这样可以确保自身业务处理完成后才会提交offset。

5. unclean.leader.election.enable

这个参数表明了什么样的副本才有资格竞争Leader,如果设置成true,那么则有可能选出一个差很多数据的副本成为新的Leader,这必然会造成数据丢失,此值默认是false,建议也设置成false。

6. replication.factor

这个参数用来表示分区的副本数,自然也就是保存消息的副本数,这也是消息可用性最基本的保障,建议大于等于3,默认是1。

总结

可以看出,要想确保Kafka消息不丢失,Consumer、Producer以及Broker都需要做好各自所负责的部分,Producer需要确保消息成功发送到Broker端,Broker端则要确保消息的成功落盘、多副本、持久化,Consumer端则要自己对自己负责,对于已提交的offset的消息都是自己真正消费过的。