文章目录
- 前言
- 消息丢失的场景
- 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的消息都是自己真正消费过的。