14 | 幂等生产者和事务生产者是一回事吗?

本文深入探讨Kafka的幂等性和事务性生产者,解析这两种特性如何确保消息的精确一次交付。幂等性Producer通过防止重复消息确保单分区的幂等性,而事务型Producer则通过原子性写入多个分区并支持跨会话的精确一次处理。启用幂等性只需设置enable.idempotence参数,而事务型Producer还需设置transactional.id并使用事务API进行消息提交。
摘要由CSDN通过智能技术生成


Kafka 核心技术与实战

客户端实践及原理剖析

14 | 幂等生产者和事务生产者是一回事吗?

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

  • 最多一次(at most once):消息可能会丢失,但绝不会被重复发送。
  • 至少一次(at least once):消息不会丢失,但有可能被重复发送。
  • 精确一次(exactly once):消息不会丢失,也不会被重复发送。

Kafka 默认提供的交付可靠性保障是第二种,即至少一次。

若消息成功“提交”,但 Broker 的应答没有成功发送回 Producer 端(比如网络出现瞬时抖动),那么 Producer 就无法确定消息是否真的提交成功了。因此,它只能选择重试,也就是再次发送相同的消息。这就是 Kafka 默认提供至少一次可靠性保障的原因,不过这会导致消息重复发送。

Kafka 也可以提供最多一次交付保障,只需要让 Producer 禁止重试即可。这样一来,消息要么写入成功,要么写入失败,但绝不会重复发送。

Kafka 如何才能做到精确一次?简单来说,这是通过两种机制:幂等性(Idempotence)事务(Transaction)

什么是幂等性(Idempotence)?

幂等性指的是某些操作或函数能够被执行多次,但每次得到的结果都是不变的。

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

幂等性 Producer

在 Kafka 中,Producer 默认不是幂等性的,但可以创建幂等性 Producer(0.11.0.0 版本引入的新功能)。在 0.11 之前,Kafka 向分区发送数据时,可能会出现同一条消息被发送了多次,导致消息重复的情况。在 0.11 之后,指定 Producer 幂等性的方法很简单,仅需要设置一个参数即可,即 props.put(“enable.idempotence”, ture),或 props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true)

enable.idempotence 被设置成 true 后,Producer 自动升级成幂等性 Producer,其他所有的代码逻辑都不需要改变。底层具体的原理很简单,就是经典的用空间去换时间的优化思路,即在 Broker 端多保存一些字段,当 Producer 发送了具有相同字段值的消息后,Broker 能够自动知晓这些消息已经重复了,于是可以在后台默默地把它们“丢弃”掉。

幂等性 Producer 的作用范围:

  • 只能保证单分区上的幂等性,即一个幂等性 Producer 能够保证某个主题的一个分区上不出现重复消息,它无法实现多个分区的幂等性。
  • 只能实现单会话上的幂等性,不能实现跨会话的幂等性。会话可以理解为 Producer 进程的一次运行,当重启了 Producer 进程之后,这种幂等性保证就丧失了。

如果想实现多分区以及多会话上的消息无重复,就需要事务(transaction)或者依赖事务型 Producer这也是幂等性 Producer 和事务型 Producer 的最大区别!

事务型 Producer

Kafka 自 0.11 版本开始也提供了对事务的支持,目前主要是在 read committed 隔离级别上做事情。它能保证多条消息原子性地写入到目标分区,同时也能保证 Consumer 只能看到事务成功提交的消息。

事务型 Producer 能够保证将消息原子性地写入到多个分区中。这批消息要么全部写入成功,要么全部失败。另外,事务型 Producer 也不惧进程的重启,Producer 重启回来后,Kafka 依然保证它们发送消息的精确一次处理。

设置事务型 Producer 的方法如下:

  • 设置 enable.idempotence = true。
  • 设置 Producer 端参数 transactional. id(最好为其设置一个有意义的名字)。
  • 在 Producer 代码中做一些调整,如这段代码所示:
producer.initTransactions();
try {
    producer.beginTransaction();
    producer.send(record1);
    producer.send(record2);
    producer.commitTransaction();
} catch (KafkaException e) {
    producer.abortTransaction();
}

和普通 Producer 代码相比,事务型 Producer 的显著特点是调用了一些事务 API,如 initTransactionsbeginTransactioncommitTransactionabortTransaction,它们分别对应事务的初始化、事务开始、事务提交以及事务终止。

这段代码能够保证 Record1 和 Record2 被当作一个事务统一提交到 Kafka,要么它们全部提交成功,要么全部写入失败。实际上即使写入失败,Kafka 也会把它们写入到底层的日志中,也就是说 Consumer 还是会看到这些消息。因此在 Consumer 端,读取事务型 Producer 发送的消息需要设置 isolation.level 参数的值即可。当前这个参数有两个取值:

  • read_uncommitted:这是默认值,表明 Consumer 能够读取到 Kafka 写入的任何消息,不论事务型 Producer 提交事务还是终止事务,其写入的消息都可以读取。很显然,如果用了事务型 Producer,那么对应的 Consumer 就不要使用这个值。
  • read_committed:表明 Consumer 只会读取事务型 Producer 成功提交事务写入的消息。当然了,它也能看到非事务型 Producer 写入的所有消息。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久违の欢喜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值