概述
-
at most once模式 基本思想是保证每一条消息commit成功之后,再进行消费处理; 设置自动提交为false,接收到消息之后,首先commit,然后再进行消费 -
at least once模式 基本思想是保证每一条消息处理成功之后,再进行commit; 设置自动提交为false;消息处理成功之后,手动进行commit; -
exactly once模式 核心思想是发送端数据发送成功,并且成功的消息只发送一次(重复的数据被服务器拒绝掉);消费端再进行at most once模式消费。
消费者的三种模式是从消费者角度衡量次数的。但是其实现却依赖生产者,因为生产者可能发送丢失数据或发送重复数据的情况:
-
at most once(消费者最多收到一次消息,0--1次 ) 特点:不会重复发送,可能消息丢失 ,acks = 0 可以实现。 acks=0 保证producer往leader只发送一次,不管是否发送成功,因此可能丢数据,但不会重复发送 -
at least once(消费者至少收到一次消息,1--多次 ) 特点:会重复发送,消息不会丢失,ack = all 或-1可以实现。 -
exactly once(消费者刚好收到一次消息) 特点:不会重复发送,消息不会丢失,at least once 加上消费者幂等性可以实现,还可以用kafka生产者的幂等性来实现。
回顾ack配置
当producer向leader发送数据时,可以通过request.required.acks参数来设置数据可靠性的级别:
-
1(默认):这意味着producer在ISR中的leader已成功收到的数据并得到确认后发送下一条message。如果leader宕机了,则会丢失数据。可能丢数据,但可能重复数据。最无用,2个缺点都占到了,因此,不会用到该模式来解决本文的主题。 -
0:这意味着producer无需等待来自broker的确认而继续发送下一批消息。这种情况下数据传输效率最高,但是数据可靠性确是最低的。可能丢数据,不会重复发送 因为0模式下,重试机制失效。 -
-1或all:producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成,可靠性最高。但是这样也不能保证数据不丢失,比如当ISR中只有leader时,这样就变成了acks=1的情况。 不丢数据,但可能重复数据。
开启失败重试,可能导致发送重复数据。
幂等性
幂等性:是指producer无论向broker发送了多少条重复的消息,broker只会持久化一条。
因为发送端重试导致的消息重复发送问题,kafka的幂等性可以保证重复发送的消息只接收一次,只需在生产者加上参数 props.put(“enable.idempotence”, true) 即可,默认是false,表示不开启 。
具体实现原理是,kafka每次发送消息会生成PID和Sequence Number,并将这两个属性一起发送给broker,broker会将PID和Sequence Number跟消息绑定一起存起来,下次如果生产者重发相同消息,broker会检查PID和Sequence Number,如果相同不会再接收。
PID:每个新的 Producer 在初始化的时候会被分配一个唯一的 PID,这个PID 对用户完全是透明的。生产者如果重启则会生成新的PID。
Sequence Number:对于每个 PID,该 Producer 发送到每个 Partition 的数据都有对应的序列号,这些序列号是从0开始单调递增的。
kafka中幂等性存在的问题
幂等性只解决了当前的会话且当前的分区的幂等性。跨分区、会话不能实现精准一次性投递写入。
当producer重启后,broker分配的PID(producer_id)会发生变化。切换分区后,Patition也发生了变化。最终导致<PID,Patition,SeqNumber>作为主键的key也会发生变化。
参考
Kafka 0.11.0.0 是如何实现 Exactly-once 语义的
|