Interviewer: How do Kafka transactions work?

I. Overview

Let's start by reviewing the concept of transactions: either all succeed or all fail! The same goes for Kafka transactions.

After Kafka 0.11.0.0, major features - idempotency and transactions were introduced. Why do we talk about idempotency in transactions? Because transactions are actually implemented based on idempotency, we must understand how idempotency works before understanding how transactions work.

This article strives to make the reader understand the workflow of the transaction in the most concise language, but will not delve into the principle too much.

The main contents of this article are:

  • What is idempotency? How to turn on idempotency?
  • How does idempotency work?
  • What is a Kafka transaction? How to start a transaction?
  • How do Kafka transactions work?

2. Idempotency

No matter how many times the Producer sends repeated data to the Broker, the Broker will only persist one piece of data to ensure that the data will not be repeated. Idempotency can be enable.idempotenceturned off , why is it turned off, because it is turned on by default!

1. How idempotency works

The working principle of idempotency is very simple, each message has a "primary key", which consists of <PID, Partition, SeqNumber>, they are:

  • PID : ProducerID, when each producer starts, Kafka will assign it an ID, ProducerID is the unique identifier of the producer, it should be noted that Kafka restart will also reassign PID
  • Partition : The partition number to which the message needs to be sent
  • SeqNumber : The producer, he will record the messages he sends and assign them an auto-incrementing ID, this ID is the SeqNumber, which is the unique identifier of the message

对于主键相同的数据,Kafka 是不会重复持久化的,它只会接收一条,但由于是原理的限制,幂等性也只能保证单分区、单会话内的数据不重复,如果 Kafka 挂掉,重新给生产者分配了 PID,还是有可能产生重复的数据,这就需要另一个特性来保证了——Kafka 事务。

image-20220719151131299

三、Kafka 事务

Kafka 事务基于幂等性实现,通过事务机制,Kafka 可以实现对多个 Topic 、多个 Partition 的原子性的写入,即处于同一个事务内的所有消息,最终结果是要么全部写成功,要么全部写失败。

Kafka 事务分为生产者事务和消费者事务,但它们并不是强绑定的关系,消费者主要依赖自身对事务进行控制,因此这里我们主要讨论的是生产者事务。

1. 如何开启事务?

在详细介绍事务的原理之前,我们先来看一个简单的事务用例。

创建一个 Producer,指定一个事务 ID:

Properties properties = new Properties();
properties.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
properties.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
properties.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
//设置事务ID,必须
properties.setProperty(ProducerConfig.TRANSACTIONAL_ID_CONFIG, "transactional_id_1");
KafkaProducer<String, String> producer = new KafkaProducer<>(properties);

使用事务发送消息:

// 初始化事务
producer.initTransactions();
// 开启事务
producer.beginTransaction();
//发送10条消息往kafka,假如中间有异常,所有消息都会发送失败
try {
    for (int i = 0; i < 10; i++) {
        producer.send(new ProducerRecord<>("topic-test", "a message" + i));
    }
}
// 提交事务
producer.commitTransaction();
} catch (Exception e) {
    // 终止事务
    producer.abortTransaction();
} finally {
    producer.close();
}

2. 事务的工作原理

下图,事务的工作流程,自制:

image-20220720093844921

1)启动生产者,分配协调器

我们在使用事务的时候,必须给生产者指定一个事务 ID,生产者启动时,Kafka 会根据事务 ID 来分配一个事务协调器(Transaction Coordinator) 。每个 Broker 都有一个事务协调器,负责分配 PID(Producer ID) 和管理事务。

事务协调器的分配涉及到一个特殊的主题 __transaction_state,该主题默认有50个分区,每个分区负责一部分事务;Kafka 根据事务ID的hashcode值%50 计算出该事务属于哪个分区, 该分区 Leader 所在 Broker 的事务协调器就会被分配给该生产者。

分配完事务协调器后,该事务协调器会给生产者分配一个 PID,接下来生产者就可以准备发送消息了。

2)发送消息

生产者分配到 PID 后,要先告诉事务协调器要把详细发往哪些分区,协调器会做一个记录,然后生产者就可以开始发送消息了,这些消息与普通的消息不同,它们带着一个字段标识自己是事务消息。

当生产者事务内的消息发送完毕,会向事务协调器发送 Commit 请求,此时生产者的工作已经做完了,它只需要等待 Kafka 的响应。

3)确认事务

事务协调器收到生产者的事务提交请求后,会先将提交信息持久化到事务主题,持久化成功后,服务端就立即发送成功响应给 Producer。然后事务协调器会跟每个涉及到的分区进行通信,当所有分区都确认事务已经完成时,事务协调器会持久化这一结果,此时事务正式结束。

四、写在最后

本文力求以最简明的语言让读者明白事务的工作流程,读起来「不累」,但实际上底层发生的事情任然有很多,我们这里不做过深的探究,感兴趣的同学可以根据不同的节点去进一步深入了解。

Kafka 专栏已经更新了三期啦:

  1. 「Kafka 专栏」- 001 Kafka 概述
  2. 「Kafka 专栏」- 002 Kafka 生产者详解
  3. 「Kafka专栏」- 003 生产者常用的调优手段

加餐:

  1. 本期:面试官:Kafka 事务是如何工作的?

本系列长期更新,内容根据资料整理和个人理解重新整理输出,原创保证。我是蛋糕,致力于以体系化的方式分享知识,点个关注不迷路!

Guess you like

Origin juejin.im/post/7122295644919693343