Kafka的幂等性是什么意思,如何实现呢?

6ee3137bba20f709d1766dac39fd3ca2.gif

点击卡片“大数据实战演练”,选择“设为星标”或“置顶”

回复“资料”可领取独家整理的学习资料!

293d142a8564188247bf6a72c2759430.png

516b6b9d591adf96ffca46f23d4956c2.png

作者:刘不二
原文链接:https://juejin.cn/post/6938998510788280333
博客内有很多系列,文章由浅入深,推荐关注!

幂等”这个词原是数学领域中的概念,指的是某些操作或函数能够被执行多次,但每次得到的结果都是不变的。

在命令式编程语言(比如 C)中,若一个子程序是幂等的,那它必然不能修改系统状态。这样不管运行这个子程序多少次,与该子程序关联的那部分系统状态保持不变。

在函数式编程语言(比如 Scala 或 Haskell)中,很多纯函数(pure function)天然就是幂等的,它们不执行任何的 side effect。

幂等性有很多好处,其最大的优势在于我们可以安全地重试任何幂等性操作,反正它们也不会破坏我们的系统状态。

一、背景

在很多系统中消息重复是不被允许的,例如一些业务结算平台(如物流平台、银行结算平台等)

为了解决重试导致的消息重复、乱序问题,kafka引入了幂等消息。幂等消息保证producer在一次会话内写入同一个partition内的消息具有幂等性,也就是说消息不会重复。

Kafka的幂等性其实就是将原来需要在下游系统中进行的去重操作放在了数据上游kafka 中。

二、至少一次语义

所谓的消息交付可靠性保障,是指 Kafka 对 Producer 和 Consumer 要处理的消息提供什么样的承诺。常见的承诺有以下三种:

  1. 最多一次(at most once):消息可能会丢失,但绝不会被重复发送。

  2. 至少一次(at least once):消息不会丢失,但有可能被重复发送。

  3. 精确一次(exactly once):消息不会丢失,也不会被重复发送。

Kafka 默认提供的交付可靠性保障是即至少一次,因为 kafka 的 producer 在消息发送失败(没有接收到 kafka broker 的 ack 信息)的时候则会进行重试,这就是kafka 为什么默认提供的是至少一次的交付语义,但是这样可能导致消息重复。

Kafka 也可以提供最多一次交付保障,只需要让 Producer 禁止重试即可。这样一来,消息要么写入成功,要么写入失败,但绝不会重复发送。我们通常不会希望出现消息丢失的情况,但一些场景里偶发的消息丢失其实是被允许的,相反,消息重复是绝对要避免的。此时,使用最多一次交付保障就是最恰当的。

无论是至少一次还是最多一次,都不如精确一次来得有吸引力。大部分用户还是希望消息只会被交付一次,这样的话,消息既不会丢失,也不会被重复处理。或者说,即使 Producer 端重复发送了相同的消息,Broker 端也能做到自动去重。在下游 Consumer 看来,消息依然只有一条,而这就是我们今天要介绍的幂等性

三、使用方法

producer 默认不是幂等性的,但我们可以创建幂等性 Producer。它其实是 0.11.0.0 版本引入的新功能。在此之前,Kafka 向分区发送数据时,可能会出现同一条消息被发送了多次,导致消息重复的情况。

在 0.11 之后,指定 Producer 幂等性的方法很简单,仅需要设置一个参数即可,即

props.put(“enable.idempotence”, ture),

或 

props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true)。

enable.idempotence 被设置成 true 后,Producer 自动升级成幂等性 Producer,其他所有的代码逻辑都不需要改变。

Prodcuer 幂等性对外保留的接口非常简单,其底层的实现对上层应用做了很好的封装,应用层并不需要去关心具体的实现细节,对用户非常友好。

四、原理

Kafka 自动帮你做消息的重复去重,底层具体的原理很简单,就是经典的用空间去换时间的优化思路,即在 Broker 端多保存一些字段。

当 Producer 发送了具有相同字段值的消息后,Broker 能够自动知晓这些消息已经重复了,于是可以在后台默默地把它们“丢弃”掉。

五、具体实现

1、区分producer会话

producer 每次启动后,首先向 broker 申请一个全局唯一的 pid,用来标识本次会话,这个 ProducerID 对客户端使用者是不可见的。

重启之后标识 producer 的 PID 就变化了,broker 就不认识,所以幂等性是只能在单次会话内的。

2、Sequence Number

对于每个PID,该 Producer 发送数据的每个<Topic, Partition>都对应一个从 0 开始单调递增的 Sequence Number,Broker 端在缓存中保存了这 seq number 。

对于接收的每条消息,如果其序号比 Broker 缓存中序号大于 1 则接受它,否则将该条消息丢弃,这样就保证了消息重复提交,但在下游 Consumer 看来,消息依然只有一条的目的。

但是只能保证单个 Producer 对于同一个 <Topic, Partition> 的 Exactly Once 语义,不能保证单个 Producer 同一个 topic 不同的 partition 幂等。

3、producer重试与消息检测

producer在收到明确的的消息丢失ack,或者超时后未收到ack,要进行重试。

重试的时候sequence number不变,因为sequence number在第一次发送的时候已经确定了,重试只是重新发送。

new_seq=old_seq+1: 正常消息;
new_seq<=old_seq : 重复消息;
new_seq>old_seq+1: 消息丢失;

六、使用范围

生产者重启时 PID 就会发生变化,同时不同的分区(Partition)也具有不同的编号,所以生产者幂等性无法保证跨分区和跨会话的 Exactly Once。

七、单分区的特性

首先,它只能保证单分区上的幂等性,即一个幂等性 Producer 能够保证某个主题的一个分区上不出现重复消息,它无法实现多个分区的幂等性。

一个幂等性的producer,只保证单分区的幂等性,而producer的消息会发给一个主题的多个分区,这就是为什么不能保证整个Topic的幂等了。

其实这里有一个问题值得思考,那就是为什么幂等性是针对单分区的?

八、单会话的特性

它只能实现单会话上的幂等性,不能实现跨会话的幂等性。这里的会话,你可以理解为 Producer 进程的一次运行。当你重启了 Producer 进程之后,这种幂等性保证就丧失了。

原因

重启之后标识 producer 的 PID 就变化了,broker 就不认识了——这个是幂等性的另一个限制条件,无法实现跨会话的幂等性。

解决方案

如果想实现多分区以及多会话上的消息无重复,就是事务(transaction)或者依赖事务型 Producer。

这也是幂等性 Producer 和事务型 Producer 的最大区别!

九、幂等为什么不支持跨会话和多分区

1、跨会话

不支持跨会话的原因是重启之后标识producer的PID就变化了,这就导致broker无法根据这个条件去去判断是否重复。

2、跨分区

我们知道在某一个partition 上判断是否重复是通过一个递增的sequence number,也就是说这个递增是针对当前特定分区的,如果你要是发送到其他分区上去了,那么递增关系就不存在了。

3、思考
  • retry会保证发送到同一个分区吗?

  • 什么情况下单分区的幂等能保证全局的幂等?

十、总结

本文主要介绍了什么是幂等以及它的实现原理,以及幂等的不足之处不支持跨会话和跨分区,优点的话也很明显,使用方便简单。

----------  END  ----------

往期推荐

Kafka精进 | Producer端核心参数及调优建议

推荐 | 颜值与功能双在线的 Zookeeper 可视化工具:PrettyZoo

hadoop之yarn命令详解

悄悄掌握 Kafka 常用命令,再也不用全网搜索了(建议收藏)

解惑 | kafka集群三节点下,挂掉一个节点,为什么消费者消费不到数据了

kafka 如何对 topic 分区 replica leader 进行负载均衡

必会 | 教你如何重新分布kafka分区、增加分区副本数

解惑 | 为什么我根据时间戳获得的offset为空呢?

最后说一句(求关注,别白嫖我)

扫一扫,我们的故事就开始了。

da998575d0ba381de54905661cf4a57b.png

文章有用,点赞、转发、在看都是一种支持,求三连

另外公众号改变了推送规则,大家看文章不要忘记点击最下方的在看,点赞按钮,这样微信自动识别为常看公众号,否则很可能推送的文章可能淹没在别的文章找不到,谢谢大家。

f6d8889f92ce8440bc74c718d9669873.png

                   动动小手,让更多需要的人看到~

86c03d9029e082fa35ed4d0dcc2140b3.gif

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kafka幂等性生产者是一种可以保证消息只被发送一次的生产者。Kafka幂等性生产者可以避免由于生产者重试机制导致的重复消息和由于网络问题导致的消息丢失等问题,提高了Kafka的可靠性和稳定性。 Kafka幂等性生产者主要通过以下两个机制来实现: 1. 序列号:每个消息都有一个唯一的序列号,序列号由生产者自动生成。生产者在发送消息时,会将消息的序列号和其他元数据一起发送到Kafka broker。Kafka broker会根据序列号来判断消息是否重复,并保证重复消息不会被写入到Kafka的日志中。 2. 重试缓存:如果生产者在发送消息时发生错误,会进行重试。Kafka幂等性生产者会将需要重试的消息缓存到重试缓存中,并在下一次重试时将缓存中的消息重新发送。由于消息具有唯一的序列号,重试缓存可以避免重复发送相同的消息。 Kafka幂等性生产者在保证消息只被发送一次的同时,也需要注意以下几点: 1. 序列号的唯一性:为了保证序列号的唯一性,生产者需要为每个消息生成唯一的序列号。可以使用时间戳、UUID等方式来生成序列号。 2. 序列号的连续性:为了保证序列号的连续性,生产者需要在发送消息之前查询数据库或者使用缓存等方式来获取上一条消息的序列号。可以使用AtomicLong等数据结构来保证序列号的连续性。 3. 性能影响:由于需要对每条消息进行序列化和添加序列号等操作,Kafka幂等性生产者的性能会受到一定的影响。因此,在使用Kafka幂等性生产者时,需要根据具体的应用场景和需求来权衡可靠性和性能的平衡。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值