可以使用 Apache Kafka“无限保留策略”作为具有 CQRS 的事件源系统的基础吗?

ton*_*008 6 cqrs event-sourcing apache-kafka eventsource apache-kafka-streams

我目前正在评估设计/实施事件溯源 + CQRS 系统设计架构方法的选项。由于我们想将 Apache Kafka 用于其他方面(正常的发布 -订阅消息 + 流处理),下一个合乎逻辑的问题是,“我们可以使用 Apache Kafka 存储作为 CQRS 的事件存储吗?”,或者更重要的是明智的决定?

现在我不确定这一点。这个来源似乎支持它:https : //www.confluent.io/blog/okay-store-data-apache-kafka/

这个其他来源建议反对:https : //medium.com/serialized-io/apache-kafka-is-not-for-event-sourcing-81735c3cf5c

在我目前的测试/实验中,我遇到了与第二个来源描述的问题类似的问题,这些问题是:

  1. 重构实体: Kafka 似乎不支持快速检索/搜索主题内的特定事件(例如:与订单历史相关的所有命令 - 重建实体实例所必需的,似乎需要扫描所有主题的事件并仅过滤那些与某些实体实例标识符匹配的事件,这是不行的)。[另一个人似乎得出了类似的结论:Query Kafka topic for specific record——也就是说,这是不可能的(不依赖一些hacky技巧)]
  2. - 写入一致性: Kafka 不支持其存储中的事务原子性,因此在将事件异步导出到 Kafka 队列之前,将具有某种锁定方法(通常是乐观锁定)的 DB 放入数据库似乎是一种常见的做法(我可以接受这个)不过,第一个问题对我来说更为重要)。
  3. 分区问题:在Kafka文档中,提到“顺序保证”,只存在于“主题的分区”中。同时他们也说分区是并行的基本单位,换句话说,如果你想并行化工作,把消息传播到分区(当然还有broker)。但这是一个问题,因为事件源系统中的“事件存储”需要订单保证,所以这意味着如果我绝对需要订单保证,我不得不在这个用例中只使用 1 个分区。这样对吗?

尽管这个问题有点开放,但实际上是这样的:您是否使用 Kafka 作为事件源系统上的主要事件存储?您如何处理从其命令历史记录中重组实体实例的问题(鉴于该主题有数百万个条目扫描所有集合不是一种选择)?您是否只使用了 1 个分区来牺牲潜在的并发消费者(假设订单保证仅限于特定主题分区)?

任何具体的或一般的反馈都将不胜感激,因为这是一个复杂的话题,有几个考虑因素。

提前致谢。

编辑 6 年前这里有一个类似的讨论: Using Kafka as a (CQRS) Eventstore。好主意? 当时的共识也存在分歧,很多人认为这种方法很方便,提到了 Kafka 如何在本地处理大量实时数据。尽管如此,问题(至少对我而言)与此无关,而是与 Kafka 重建实体状态的能力有多么不方便有关 - 要么通过将主题建模为实体实例(其中主题数量呈指数级增长是不希望的) ,或通过建模主题 es 实体类型(其中主题内的大量事件使重建非常缓慢/不切实际)。

rad*_*dai 4

您的理解大部分是正确的:

  1. kafka没有搜索。绝对不是通过钥匙。有一个时间戳的寻求,但它不完美并且不适合你想要做的事情。
  2. 如今,kafka 实际上支持有限形式的事务(仅查看一次),尽管如果您与 kafka 之外的任何其他系统进行交互,它们将毫无用处。
  3. kafka 中任何事物(事件排序、可用性、复制)的单位都是分区。无法保证同一主题的跨分区。

所有这些都不会阻止应用程序使用 kafka 作为其状态的事实来源,只要:

  1. 您的问题可以“分片”到主题分区中,这样您就不必关心跨分区的事件顺序
  2. 如果/当您丢失本地状态作为引导程序时,您愿意“重播”整个分区。
  3. 您使用日志压缩主题来尝试限制其大小(因为您需要将它们重播到引导程序,请参阅上面的点)

samza 和 (IIUC) kafka-streams 都使用日志压缩的 kafka 主题来支持它们的状态存储。在 kafka 内部,偏移量和消费者组管理存储为日志压缩主题,代理在内存中保存“物化视图”——当__consumer_offsets代理之间移动分区的所有权时,新领导者会重播该分区以重建此视图。