Apache Pulsar分布式事务机制


Pulsar 事务 (txn) 使事件流应用程序能够在一个原子操作中消费、处理和生成消息。开发此功能的原因可以总结如下。

随着流处理的兴起,对具有更强处理保障的流处理应用的需求也随之增长。
例如,在金融行业,金融机构使用流处理引擎为用户处理借记和贷记。这种类型的用例要求每条消息都只处理一次,无一例外。
换句话说,如果流处理应用程序消费消息 A 并将结果生成为消息 B (B = f(A)),那么恰好一次处理保证意味着只有当且仅当 B 是时,A 才能被标记为已消费成功生产,反之亦然。
Pulsar事务API加强了流处理的消息交付语义和处理保证。
它使流处理应用程序能够在一个原子操作中消费、处理和生产消息。
这意味着,一个事务中的一批消息可以从许多主题分区接收、产生并被确认。
一个事务中涉及的所有操作的成功或失败都是一个单一的原子单元。
 
Pulsar生产者的局限性
通过使用Pulsar的idempotent幂等生产者可以避免数据丢失或重复,但是它并不能为跨多个分区的写入提供保证。

在Pulsar中,最高级别的消息传递保证是在一个单一分区使用具有精确一次语义的idempotent生产者,也就是说,每个消息被精确地持久化一次,没有数据损失和重复。然而,这个解决方案也有一些局限性。

  • 由于序列ID单调递增,该方案仅适用于单个分区和单个生产者会话内(即生产一条消息),因此在向一个或多个分区生产多条消息时没有原子性。
    在这种情况下,如果在生产和接收消息的过程中出现一些故障(例如,client/broker/bookie 崩溃、网络故障等),消息会被重新处理和重新传递,这可能会导致数据丢失或数据重复:
    • 对于生产者:如果生产者重试发送消息,一些消息会被持久化多次;如果生产者不重试发送消息,一些消息会被持久化一次,而另一些消息会丢失。
    • 对于消费者:由于消费者不知道broker是否收到消息,消费者可能不会重试发送ack,导致收到重复消息。
  • 类似地,对于 Pulsar Function,它只保证单个事件上的幂等函数的语义只有一次,而不是处理多个事件或产生多个可能发生的结果。
    例如,如果一个函数接受多个事件并产生一个结果(例如,窗口函数),则该函数可能会在产生结果和确认传入消息之间失败,甚至在确认单个事件之间失败,这会导致所有(或部分)传入消息被重新传递和重新处理,并生成新的结果。
    但是,许多场景需要跨多个分区和会话的原子保证。
  • 消费者需要依赖更多的机制来一次确认(ack)消息。
    例如,消费者需要存储 MessgeID 及其确认状态。主题卸载后,订阅可以在再次加载主题时恢复内存中这个MessgeID的acked状态。