kafka 事务模型

1. 事务支持

kafka 在 0.11.0.0 版本中添加了事务支持,同时增加了 ‘精确一次’ 的发送语义用于支持事务模型:

  1. Exactly once ,this is what people actually want, each message is delivered once and only once
  2. 简单的解释下 kafka 如何支持 ’精确一次‘ 的语义:
    (1)生产者执行 initTransactions() ,在事务协调者获取当前生产者的 producer Id,这个 ID 本质是在 zookeeper 上获取 的,每台 broker 机器有 1000 个 ID 的范围选择,如果使用完毕在 ZK 上递增增加范围,为了保证 producer Id 不重复
    (2)broker 记录了 producer 的 代 的信息,同时 producer 和 broker 同时记录当前的生产者在所在的代中 sequence number,如果 number 不匹配则拒绝消息的发送同时告知 producer 重新获取 ID 和 代信息并重置 sequence number
    (3)broker 根据记录的 producer ID 和 对应的 sequence number 来去重,已经发送过的消息 number 不会再次记录

参考: kafka cwiki.apache.org .

2. 事务目的

  1. 主要了解决 kafka-stream 存在的 消费-处理-发送 模型,因为对于 kafka 来说这是一个原子性的动作,这其中一个环节失败会重试的会导致业务重复处理,例如 计算某些业务统计值,处理完毕后发送消费 offset 失败但是消息发送成功,会导致重复计算。
    在这里插入图片描述
  2. 处理不了的问题:业务系统的数据库等数据源并不能和 kafka 事务联系在一起,它并没有考虑业务系统的事务问题,它只解决了自己的系列产品的原子性语义。例如 Rocket MQ 就提供了简单的和业务系统关联的事务接口

3. API

 Properties props = new Properties();
 props.put("transactional.id", "test-transactional");
 Producer<String, String> producer = new KafkaProducer<>(props);
 producer.initTransactions();
 try {
       producer.beginTransaction();
       producer.send(new ProducerRecord<>(...));
       producer.send(new ProducerRecord<>(...));
       producer.commitTransaction();
  } catch (ProducerFencedException e1) {
       producer.close();
  } catch (KafkaException e2) {
       producer.abortTransaction();
  }

使用上非常简单,配置 transactional.id(如果使用事务,必须且唯一,事务协调者用于处理与其关联的事务),和 JDBC 的事务使用上很相似

4. 事务模型

Kafka 事务本质是 2PC 模式,消费 offset 本质上也是发送消息到指定的 topic 中:
在这里插入图片描述
流程说明:

  • A:生产者使用 t.id 请求协调者获取对应的 producer id 和年代周期
  • B:协调者接受到 t.id 的初始化请求后进行 producer id 的生成并返回,同时让已存在的 session
    失效,同一个 t.id 只能有一台机器使用,并增加年代周期,返回对应的 sequence number,同时将此
    初始化请求写入 transaction log,防止协调者宕机使该 2PC 事务挂起,并将状态变更为 ongoing
  • C:发送一条 prepare 消息事给务协调者,代表第一阶段的 prepare,这里不是由协调者主动发起,而是
    由客户端代替协调者的职责发起,请求协调者准备 prepare,因为只有客户端知道需要发送的消息信息
  • D:协调者同意 prepare 后,代替协调者发送消息至对应的 broker 的 topic queue log 中,不过增加消息
    增加了事务标识,且状态为未提交,此时如果消费者并不是消费已提交的事务消息,会收到此消息
  • E:当 producer 告知 协调者事务提交后,协调者开始第二阶段工作,根据 D 接受的 prepare 消息,找到对应
    的 topic queue,并发送事务提交标志消息(txn remarker)至该 queue log,代表事务提交,同时该
    队列会更新 LSO(最后提交的事务的 offset),这样就可以发送至事务消费者进行消费

消费者如果配置消费已提交的隔离级别,那么 broker 会根据 LSO 发送消息至消费者,而不是普通的最低水位

5. 事务协调者模型

事务协调者类似 消费者组协调者,本质上都是利用 kafka 本身的 topic log 进行一些持久化必要信息的操作(topic log 本身提供高可用,所以不必担心信息丢失):
在这里插入图片描述
生产者开启事务后,会与自己事务协调者 queue 所属的 leader 进行通信,其实本质就是根据事务ID 进行 hash 计算的,之后的一些列 2PC 交互都与自己的协调者进行沟通,为什么选择 leader 作为协调者,因为它和组协调者一样,会在内存中缓存一些消息内容,不必每次都去读取 log 文件内容来获取。

6. 总结

kafka 的事务本质上 2PC 提交,不过发起都是由 producer 进行发起,协作者帮助记录信息,最后一步提交后才由协调者发起,标记事务消息被提交。

kafka 的事务的数据源只有自己的 topic log,如果需要和应用程序的数据源结合使用,保证事务性还需要一些额外的操作,具体如何操作之后会专门发篇文章来说明,如果使用 kafka-stream 系列产品,就可开箱即用,还是很方便的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值