使用Kafka和Cassandra进行活动来源的类别预测

时间:2019-08-06 06:43:45

标签: apache-kafka cqrs event-sourcing

我正在使用Cassandra和Kafka进行事件来源,并且效果很好。但是我最近才发现设计/设置中潜在的重大缺陷。简介:

  1. 聚合命令处理程序基本上是kafka使用者,它消耗有关主题的感兴趣消息:

    1.1收到命令时,它将加载聚合的所有事件,并为每个事件重播聚合事件处理程序,以使聚合恢复到当前状态。

    1.2根据命令和总线逻辑,然后将一个或多个事件应用于事件存储。这涉及将新事件插入cassandra中的事件存储表。这些事件会使用汇总的版本号标记-从新汇总的版本0开始,从而可以进行预测。此外,它将事件发送到另一个主题(出于投影目的)。

    1.3这些事件发布后,kafka消费者将收听该主题。该消费者将充当投影仪。当它收到感兴趣的事件时,它将加载聚合的当前读取模型。它检查接收到的事件版本是否为预期版本,然后更新读取模型。

这似乎效果很好。问题是当我想拥有EventStore所谓的类别预测时。让我们以订单汇总为例。我可以轻松地设计一个或多个读取模型pr Order。但是,例如,如果我想有一个包含30个客户最后订单的投影,那么我将需要一个类别投影。

我只是在摸索如何做到这一点。我很好奇,是否有其他人正在使用Cassandra和Kafka进行活动采购。我读过一些地方,有些人不赞成这样做。也许这就是原因。

我知道EventStore支持此内置功能。也许使用Kafka作为事件存储将是更好的解决方案。

1 个答案:

答案 0 :(得分:1)

使用这种架构,您必须在以下选项之间进行选择:

  • 每种类型的全局事件流-简单
  • 每种类型的分区事件流-可扩展

除非您的系统具有相当高的吞吐量(例如,对于所讨论的流类型,每秒至少10s或100s个事件的持续时间),否则全局流是更简单的方法。某些系统(例如事件存储)具有非常细粒度的流(例如,每个聚合实例),但又可以将它们组合成更大的流(每个流类型/类别/分区,每个多种类型的流等),以开箱即用的性能和可预测的方式实现,而通过仅要求您跟踪单个全局事件位置仍然很简单。

如果您使用Kafka进行分区:

  • 当为需要进入同一模型的不同分区处理事件时,您的投影代码将需要处理并发消费者组,这些用户组将访问相同的读取模型。根据投影的目标商店,有很多方法可以处理此问题(事务,乐观并发,原子操作等),但这对于某些目标商店来说是个问题
  • 您的投影代码将需要跟踪每个分区的流位置,而不仅仅是单个位置。如果您的投影从多个流中读取,则它必须跟踪很多位置。

使用全局流消除了这两个方面的顾虑-性能通常可能足够好。

无论哪种情况,您都可能希望将流的位置放入长期事件存储中(例如Cassandra)-您可以通过从事件流(分区的或全局的)中读取专用的进程来做到这一点。使用每个事件的全局或分区位置更新Cassandra中的事件。 (我在MongoDB中也有类似的事情-我有一个过程读取'oplog'并将oplog时间戳复制到事件中,因为oplog时间戳是完全有序的。)

另一种选择是从初始命令处理中删除Cassandra,并改用Kafka Streams:

  • 通过与分区的聚合KTable联接来处理分区的命令流
  • 计算命令结果和事件
  • 从原子上讲,KTable会使用更改后的聚合进行更新,将事件写入事件流,并将命令响应写入命令响应流。

然后,您将拥有一个下游事件处理器,该事件处理器将事件复制到Cassandra中以便于查询等(并且可以将Kafka流的位置添加到每个事件中,从而进行类别排序)。如果您不想使用Kafka进行长期事件存储,则可以帮助赶上订阅等。 (要赶上进度,您只需从Cassandra中阅读尽可能多的内容,然后从上一个Cassandra事件的位置切换到Kafka的流式播放)。另一方面,Kafka本身可以永久存储事件,因此并不一定总是如此。

我希望这有助于理解您可能会遇到的折衷和问题。