https://blog.csdn.net/z69183787/article/details/80326613
代码语言:java复制ExactlyOnce:只持久化一次,意味着每个消息对于接收者而言正好被接收一次
Ack 可以通过参数配置保证数据不丢失或不重复,但不能同时保证数据不重复也不丢失,即Exactly Once即精确的一次。
幂等性:指代Producer不论向Server发送了多少次重复数据,Server端都只会持久化一条数据。
启用幂等性,即在Producer的参数中设置enable.idempotence=true
原理:
Kafka的幂等性实现实际是将之前的去重操作放在了数据上游来做,开启幂等性的Producer在初始化的时候会被分配一个PID,
发往同一个分区(Partition)的消息会附带序列号(Sequence Number),而Broker端会对<PID,Partition,SeqNumber>做缓存,
当具有相同主键的消息的时候,Broker只会持久化一条。
注意:但PID在重启之后会发生变化,同时不同的Partition也具有不同的主键,所以幂等性无法保证跨分区跨会话的Exactly Once。
Kafka引入了Producer ID(即PID)和Sequence Number。
每个新的Producer在初始化的时候会被分配一个唯一的PID,该PID对用户完全透明而不会暴露给用户。
对于每个PID,该Producer发送数据的每个<Topic, Partition>都对应一个从0开始单调递增的Sequence Number。
Broker端也会为每个<PID, Topic, Partition>维护一个序号,并且每次Commit一条消息时将其对应序号递增。
对于接收的每条消息,如果其序号比Broker维护的序号(即最后一次Commit的消息的序号)大一,
则Broker会接受它,否则将其丢弃
1、如果消息序号比Broker维护的序号大一以上,说明中间有数据尚未写入,也即乱序,此时Broker拒绝该消息,Producer抛出InvalidSequenceNumber
2、如果消息序号小于等于Broker维护的序号,说明该消息已被保存,即为重复消息,Broker直接丢弃该消息,Producer抛出DuplicateSequenceNumber
上述设计解决了0.11.0.0之前版本中的两个问题:
1、Broker保存消息后,发送ACK前宕机,Producer认为消息未发送成功并重试,造成数据重复
2、前一条消息发送失败,后一条消息发送成功,前一条消息重试后成功,造成数据乱序