隨筆 20241023 Kafka 事务
Kafka 事务概述
-
原子性要求:在需要将数据同时发送到多个 broker 中的不同分区时,使用事务可以确保这些操作具备原子性,确保要么全部成功,要么全部失败。
-
事务标记:在开启事务时,每一个发往不同分区的消息都会被标记上相同的事务 ID 和生产者 ID(PID),以表明它们属于同一个事务。
-
事务状态存储:
- 这些与事务相关的信息(如事务 ID 和 PID)会被发送到 Kafka 的内部主题
__transaction_state
中,并存储在其某个特定的分区中。 - 这个主题用于记录和监控当前事务的状态。
- 这些与事务相关的信息(如事务 ID 和 PID)会被发送到 Kafka 的内部主题
-
TransactionCoordinator 角色:
TransactionCoordinator
是 Kafka 中负责管理事务的协调者。它实时监控__transaction_state
中的事务状态信息。- 当生产者发送消息时,接收数据的 broker 会将其接收进度和结果实时汇总到
__transaction_state
中,TransactionCoordinator 可以根据这些信息了解事务的执行情况。
-
提交与回滚:
- 一旦所有消息都成功发送并被正确处理,生产者会通知 TransactionCoordinator 提交事务。
- TransactionCoordinator 会检查与当前事务 ID 相关的所有操作的状态,确认它们是否全部完成。
- 如果所有操作都成功,事务会被提交,所有消息在业务主题中变为可见;如果有任何操作失败,事务将被回滚,确保数据的一致性和完整性。
总结
通过这种机制,Kafka 能够保证跨多个 broker 的消息发送在逻辑上的原子性和一致性。无论消息发送到多少个不同的分区,Kafka 都能通过 __transaction_state
主题和 TransactionCoordinator 来监控和管理事务的状态,确保数据的一致性和可靠性。这种设计不仅提升了 Kafka 的灵活性,还确保了在复杂的分布式系统中进行消息传递的可靠性。
Kafka 的隔离级别(Isolation Level)虽然是一个高层的概念,但其底层实现涉及到多个组件和机制。下面将详细解释 Kafka 如何在底层实现这些隔离级别,特别是 读已提交 和 读未提交 的实现方式。
1. 事务管理机制
在 Kafka 中,事务管理主要依赖于 Transaction Coordinator
,它负责管理事务的状态,并协调与消费者的消息可见性。每个生产者在发送消息时会使用一个唯一的 事务 ID,通过这个 ID 来标识属于同一事务的所有操作。
2. 关键概念
- 事务状态:在 Kafka 中,事务有多种状态,包括 Ongoing(进行中)、Committed(已提交)、和 Aborted(已回滚)。
- __transaction_state 主题:Kafka 内部使用一个名为
__transaction_state
的主题来记录所有事务的状态。当生产者发送消息时,它会将事务的相关信息(如事务 ID 和状态)写入这个主题,以便Transaction Coordinator
能够跟踪。
3. 读已提交的实现
-
消息发送:当生产者发送消息时,这些消息会被标记为“正在进行的事务”,并会写入相应的业务主题分区,但未立即对消费者可见。
-
状态更新:生产者在完成所有消息发送后,会向
Transaction Coordinator
发送提交请求。此时,Transaction Coordinator
会检查事务中所有消息的状态,并将这些消息的状态更新为 Committed。 -
消费者读取:
- 在消费者尝试读取消息时,Kafka 会检查这些消息的状态。如果消息的状态是 Committed,消费者才能读取到它们。
- 如果状态仍是 Ongoing,则这些消息将不会对消费者可见。
4. 读未提交的实现
-
消息发送:与读已提交类似,生产者可以在一个事务中发送多条消息,所有消息也会写入业务主题分区。
-
状态更新:与读已提交不同的是,在读未提交的情况下,消费者可以读取这些正在进行的事务消息。
-
消费者读取:
- 当消费者读取消息时,即使某些消息的状态是 Ongoing,它们也会被返回给消费者。
- 消费者需要自行处理这些未提交消息可能导致的不一致性。
5. Kafka 的数据存储和读取
5.1 消息存储
- Kafka 将消息存储在分区内,且每个分区是一个有序的日志文件。在这个文件中,消息在被写入时会被分配一个 offset,这个 offset 是唯一的,确保消息的顺序性。
5.2 消息的可见性
- 当事务提交时,Kafka 更新
__transaction_state
主题中的状态,以确保所有消费者能看到已提交的消息。 - 只有当事务状态更新为 Committed 时,相关的业务主题消息才会被标记为可见,供消费者读取。
6. 总结
通过将消息状态管理和事务协调集中在 Transaction Coordinator
上,Kafka 实现了对消息可见性和一致性的控制。通过使用 __transaction_state
主题,Kafka 能够在底层跟踪事务的状态,并根据配置的隔离级别决定哪些消息对消费者可见。这样设计确保了在高吞吐量的环境中,Kafka 依然能够保证消息的一致性和可靠性。
1. 提交事务之前数据没有被 broker 接收吗?没有保存到 broker 中吗?
在 Kafka 中,事务的工作方式是:
- 当你在事务中发送消息时,这些消息会被发送到对应的业务主题的分区中,但在事务提交之前,这些消息并不会被消费者看到。也就是说,虽然消息被写入到 broker 中,但它们的状态是“未提交”的,消费者无法读取这些消息。
- 具体来说,Kafka 事务的实现机制确保了在事务未提交的情况下,这些消息的“可见性”被屏蔽。Kafka 使用了一种称为“隐式提交”的方式,只有在所有相关消息都成功发送且事务提交后,这些消息才会变得可见。
2. 如果数据已经保存到对应业务 broker 中,如何不被消费者发现?提交成功后又是如何让消费者发现对应消息的呢?
- 隐式可见性:
- 在 Kafka 事务处理中,事务中的每条消息在被写入 broker 时并不会立即对消费者可见。Kafka 利用 ISOLATION LEVEL(隔离级别)来实现这一点,特别是使用 READ_COMMITTED 隔离级别。这个隔离级别确保消费者在读取消息时,只会看到那些已经提交的消息,而看不到未提交的事务中的消息。
- 消息提交:
- 一旦你调用提交事务的操作,TransactionCoordinator 会检查所有事务相关消息的状态,确认它们都成功。如果所有消息都成功,TransactionCoordinator 会将这些消息标记为已提交,这意味着它们现在对消费者可见。
- 提交成功后,这些消息会被消费者看到,消费者在下次读取消息时,就能读取到这些已提交的消息。
小结
通过这种机制,Kafka 能够确保即使在多个分区和 broker 之间进行复杂的事务操作,也能保证数据的一致性和完整性。在事务未提交的情况下,数据不会被消费者看到,从而避免了不一致的状态。而一旦事务提交,所有相关的消息会同时对消费者可见,确保了操作的原子性。