幂等性引入目的:

生产者重复生产消息。生产者进行retry会产生重试时,会重复产生消息。有了幂等性之后,在进行retry重试时,只会生成一个消息。

概述

ack设置-1之后虽然不会出现数据丢失问题,但是还会出现数据重复问题
数据重复了怎么办????
是否允许数据重复取决于场景, 有写场景重复了也没事儿,比如说记录点击事件,重复了顶多就是多记录一条数据,
但是如果是订单,充值之类的,数据重复的话,那么问题就有点严重了.
有的数据不但不能丢,还不能重复,比如说交易的场景,记录数据不能记录两份儿.

解决办法

在某个版本之前,Kafka是没有去重机制的,Kafka的Consumer消费数据就是有可能会出现重复的现象.
解决办法就是consumer会根据我们kafka消息会有一个消息唯一的全局主键,consumer在拿到这个有重复数据的时候,会在下游做一个全局去重,然后再接着处理数据.
因为全局去重的话会造成一个性能的损失.
在kafka忘了哪个版本之后,做了一个重大的改进,就是幂等性.
幂等性就是你Kafka无论发送多少条重复的数据,最终只有一条数据被处理,不会出现数据重复的问题.
你给ack 设置为-1 的话, 消息不会丢失,你发送消息重复了,也只会给你处理保存一次消息.不会造成数据的重复.
有了幂等性之后kafka就能达到 exactly once 语义. 就是消息精确一次不重复也不丢失.
如果要启用幂等性的话,需要在producer开启一个参数: enable.idompotence 设置为true即可.
全局去重和下游去重概念是差不多的,就是用一个全局唯一的主键,根据这个主键来去重复,如果你发的数据没有全局主键的话,Kafka会自动给你标记一个全局唯一的主键来保证数据的唯一性.
全局主键组成:
当你producer往你broker发送消息以后,broker除了会存储这个消息,还会储存这个消息的全局主键.这个主键包括 pid(producer id ,就是producer编号 ) Partition 和 seqnumber 来做的,Partition 和 seqnumber 来就是哪个分区的第几条消息.seqnumber可以理解为第几条消息.

上面这些东西只有在开启幂等性的配置的时候才会有,如果你不开幂等性的话,发送消息是不会有这些东西的.

假如说你producer 1 往第三个分区发送第二条消息, 此时 pid就是1 ,Partition号就是3 ,seqnumber就是 2 , 然后broker在接收的时候发现这个消息之前已经接收过了,说明是重复的,那么就会缓存一条消息. 这样消息就不会重复了.
这就是幂等性实现的基本原理.
pid就是为了区分不同的partition的一个id.

这样的全局主键存在一个问题.

当你producer重启之后producer就变了,broker就会认为是一个新的producer,当你producer挂掉了,再重启的话,此时你producer和broker之间就跨会话了. broker就会认为你是新的消息了,从而导致 幂等性失效,
第二个就是producer挂掉之后,再重启 partition也会变. 这样也会导致发送消息重复.
所以幂等性无法保证跨会话不会重复.要想跨会话保证数据不重复 就需要事务了.