Kafka 在有状态处理中验证消息

Kafka validate messages in stateful processing

我有一个应用程序,多个用户可以发送 REST 操作来修改 shared 对象的状态。 修改对象时,将发生多个操作(数据库、审计、日志记录...)。

并非所有操作都有效,例如您不能在删除对象后对其进行修改。

使用 Kafka 我在考虑以下架构:

  1. Rest 操作正在 Kafka 主题中排队。
  2. 对同一对象的操作将转到同一分区。所以对象的所有操作都将按顺序由消费者处理
  3. 消费者正在侦听分区并使用内存数据库验证操作
  4. 如果操作有效则发送到 "Valid operation topic" 否则发送到 "Invalid operation topic"
  5. 其他消费者(数据库、日志、审计)正在收听 "Valid operation topic"

我不太确定第 3 点。 我不喜欢保留所有对象状态的想法。 (我有数十亿个对象,即使一个对象的大小可以达到 10mb,我需要存储以验证其状态的内容也只有几千字节...

但是,这是常见的模式吗?否则如何验证某些操作的有效性?

另外,您会使用什么作为内存数据库?肯定要高可用,容错,支持事务(读写)。

我相信这是一个非常有效的模式,并且本质上是事件源 CQRS 模式的变体。

例如,Lagom implements their CQRS persistence in a very similar fashion(尽管基于完全不同的工具集)

几点:

  • 你对顺序操作的需求是正确的:因为你所有的状态突变都需要基于前一个突变的结果,所以它们的执行必须有很强的顺序。这种情况很常见,所以我们希望能够尽可能地水平扩展这些操作,以便每个序列操作都与许多其他序列并行发生。在您的情况下,每个共享对象都有一个这样的序列。
  • 依靠 Kafka 按键分区是实现这一点的好方法(假设您没有将 max.in.flight.requests.per.connection 设置为高于默认值 1)。在这里,Lagom 再次采用了类似的方法,将其持久实体分布在单线程中。我并不是说 Lagom 更好,我只是安慰你,事实上其他人也使用这种方法:)

  • 您的模式的一个关键方面是将命令转换为事件:在该行话中,命令被视为影响状态的请求,可能会因各种原因被拒绝。事件是对过去发生的状态更新的描述,从接收者的角度来看是无可辩驳的:事件总是说实话。您所描述的过程将是一个位于两者之间边界的控制器:它负责将命令转换为事件。

  • 从这个意义上说,您提到的 "Valid operation topic" 将是过程状态更新的事件源描述。由于它全部由 Kafka 支持,因此可以任意分区并因此可扩展,这太棒了 :)
  • 不要担心所有对象的状态大小,它必须以某种方式位于某处。由于您拥有将命令转换为事件的控制器,因此该控制器成为与该对象相关的主要真相来源,并且该控制器负责存储它:该控制器处理事件的主要存储,因此您必须满足 space 为它。您可以使用 Kafka Streams's Key value store:它们对于您的每个处理实例都是本地的,但如果您使它们持久化,它们在处理比可用 RAM 大得多的数据时没有问题。由于 RocksDB,在幕后数据被溢出到磁盘,甚至在幕后,它都是事件源到 kafka 主题,所以你的状态存储被复制,并在必要时透明地在另一台机器上重新创建

我希望这可以帮助您完成设计:)