Why transactions?

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

流处理的需求

随着流处理的兴起,对具有更强处理保证的流处理应用的需求也在增长。 例如,在金融行业,金融机构使用流处理引擎为用户处理借款和信贷。 这种类型的用例要求每条消息都只处理一次,无一例外。

换句话说,如果流处理应用程序消费消息 A 并将结果作为消息B (B = f(A)),那么恰好一次处理保证意味着当且仅当 B 被成功生产后 A 才能被标记为消费,反之亦然。

Why transactions? - 图1

Pulsar 事务 API 加强了消息传递语义和流处理的处理保证。 它使流处理应用程序能够在一个原子操作中使用、处理和生成消息。 这意味着,事务中的一批消息可以从许多主题分区接收、生成和确认。 一个事务涉及的所有操作都作为整体成功或失败。

幂等生产者的局限性

使用Pulsar幂等生产者可以避免数据丢失或重复,但它不为跨多个分区的写入提供保证。

在Pulsar中,最高级别的消息传递保证是使用 幂等生产者 在单个分区上使用恰好一次语义,即每条消息只持久化一次,不会丢失和重复。 然而,这种解决办法有一些限制:

  • 由于单调递增的序列ID,该方案仅适用于单个分区和单个生产者会话内(即生产一条消息),因此向一个或多个分区生产多条消息时没有原子性。

    在这种情况下,如果在产生和接收消息的过程中出现一些故障(例如,client/broker/bookie崩溃、网络故障等),消息会被重新处理和重新投递,这可能会导致数据丢失或数据重复:

    • 对于生产者:如果生产者重试发送消息,有些消息会被多次持久化;如果生产者不重试发送消息,一些消息会被持久化一次,而其他消息会丢失。

    • 对于消费者:由于消费者不知道代理是否收到消息,因此消费者可能不会重试发送 ack,从而导致其收到重复的消息。

  • 类似地,对于Pulsar Function,它只为单个事件的幂等函数保证恰好一次语义,而不是处理多个事件或产生多个可能完全发生的结果。

    例如,如果一个函数接受多个事件并产生一个结果(例如,窗口函数),该函数可能会在产生结果和确认传入消息之间失败,甚至在确认单个事件之间失败,这会导致所有(或部分)传入消息被重新传递和重新处理,并产生一个新的结果。

    但是,许多场景需要跨多个分区和会话的原子保证。

  • 消费者需要依赖更多的机制来确认(ack)消息一次。

    例如,消费者需要存储MessgeID及其确认(ack)状态。 卸载主题后,订阅可以在再次加载主题时恢复内存中的 MessgeID 的确认(ack)状态。