使用Kafka作为(CQRS)Eventstore。好主意?

问题描述 投票:174回答:5

虽然我之前遇到过Kafka,但我最近才意识到Kafka可能被用作CQRSeventstore)的基础。

Kafka支持的要点之一:

  • 事件捕获/存储,当然都是HA。
  • 发布/子结构
  • 能够重放事件日志,允许新订户在事后注册系统。

诚然,我不是100%精通CQRS /事件采购,但这看起来非常接近eventstore应该是什么。有趣的是:我真的找不到关于Kafka被用作事件存储的那么多,所以也许我必须遗漏一些东西。

那么,卡夫卡缺少什么东西才能成为一个好的活动商店?会有用吗?用它生产?对洞察力,链接等感兴趣

基本上,系统的状态是根据系统收到的事务/事件保存的,而不是仅仅保存系统的当前状态/快照,这是通常所做的。 (将其视为会计总帐:所有交易最终都会累加到最终状态)这允许各种很酷的事情,但只需阅读所提供的链接。

cqrs event-sourcing apache-kafka dddd
5个回答
104
投票

Kafka是一个消息传递系统,它与事件存储有很多相似之处,但引用它们的介绍:

Kafka群集保留所有已发布的消息 - 无论它们是否已被消耗 - 在可配置的时间段内。例如,如果保留设置为两天,那么在发布消息后的两天内,它可供消费,之后将被丢弃以释放空间。 Kafka的性能在数据大小方面实际上是恒定的,因此保留大量数据不是问题。

因此,虽然可以无限期地保留消息,但期望它们将被删除。这并不意味着您不能将其用作事件存储,但使用其他东西可能更好。看看EventStore的另一种选择。

UPDATE

Kafka documentation

事件源是一种应用程序设计风格,其中状态更改被记录为按时间排序的记录序列。 Kafka对非常大的存储日志数据的支持使其成为以这种风格构建的应用程序的出色后端。

UPDATE 2

使用Kafka进行事件采购的一个问题是所需主题的数量。通常在事件源中,每个实体(例如用户,产品等)存在事件流(主题)。这样,可以通过重新应用流中的所有事件来重构实体的当前状态。每个Kafka主题由一个或多个分区组成,每个分区都存储为文件系统上的目录。随着znode数量的增加,ZooKeeper也会有压力。


255
投票

我是卡夫卡的原作者之一。 Kafka将作为事件采购的日志工作得非常好。它具有容错能力,可扩展到巨大的数据大小,并具有内置的分区模型。

我们在LinkedIn使用此表单的几个用例。例如,我们的开源流处理系统Apache Samza附带built-in support用于事件采购。

我认为你没有太多关于使用Kafka进行事件采购的原因,主要是因为在Kafka最受欢迎的消费者网络空间中,事件采购术语似乎并不普遍。

我已经写了一些关于这种风格的卡夫卡用法here


31
投票

我一直回到这个QA。而且我没有发现现有的答案有细微差别,所以我添加了这个。

TL;DR. Yes or No, depending on your event sourcing usage.

我知道有两种主要的事件源系统。

下游事件处理器=是

在这种系统中,事件发生在现实世界中并被记录为事实。如仓库系统,以跟踪产品的托盘。基本上没有冲突的事件。一切都已经发生,即使它是错的。 (即,托盘123456放在卡车A上,但是计划用于卡车B.)然后通过报告机制检查事实的异常情况。 Kafka似乎非常适合这种下游事件处理应用程序。

在这种情况下,为什么Kafka人们将其作为事件采购解决方案提倡是可以理解的。因为它与已经使用的方式非常相似,例如点击流。然而,使用术语事件采购(与流处理相对)的人可能指的是第二种用法......

应用程序控制的事实来源=否

由于用户请求通过业务逻辑,这种应用程序声明自己的事件。由于两个主要原因,卡夫卡在这种情况下效果不佳。

Lack of entity isolation

此方案需要能够为特定实体加载事件流。这样做的常见原因是为业务逻辑构建一个临时写模型,用于处理请求。这样做在卡夫卡是不切实际的。使用每个实体主题可以允许这样做,但是当可能存在数千或数百万个实体时,这是不起作用的。这是由于Kafka / Zookeeper的技术限制。

以这种方式使用瞬态写入模型的主要原因之一是使业务逻辑变更便宜且易于部署。

建议使用每个类型的主题代替Kafka,但这需要为该类型的每个实体加载事件,以便为单个实体获取事件。由于您无法通过日志位置判断哪些事件属于哪个实体。即使使用Snapshots从已知的日志位置开始,这也可能是大量的事件。

Lack of conflict detection

其次,由于针对同一实体的并发请求,用户可以创建竞争条件。保存冲突事件并在事后解决它们可能是非常不受欢迎的。因此,能够防止冲突事件非常重要。为了扩展请求负载,通常使用无状态服务,同时使用条件写入防止写入冲突(仅在最后一个实体事件为#x时写入)。又名乐观并发。 Kafka不支持乐观并发。即使它在主题级别支持它,它也需要一直到实体级别才能生效。要使用Kafka并防止冲突事件,您需要在应用程序级别使用有状态的序列化编写器。这是一个重要的架构要求/限制。

Further information


每条评论更新

该评论已被删除,但问题是:人们用什么来进行事件存储呢?

似乎大多数人在现有数据库之上推出自己的事件存储实现。对于非分布式方案,如内部后端或独立产品,well-documented如何创建基于SQL的事件存储。并且在各种数据库之上有可用的库。还有EventStore,它是为此目的而建造的。

在分布式场景中,我看到了几种不同的实现。 Jet的Panther project uses Azure CosmosDB,带有Change Feed功能,通知听众。我在AWS上听到的另一个类似的实现是使用DynamoDB及其Streams功能来通知侦听器。分区键可能应该是用于最佳数据分发的流ID(以减少过度配置的数量)。但是,在Dynamo中跨流的完整重播是昂贵的(阅读和成本方面)。因此,这个impl也被设置为Dynamo Streams将事件转储到S3。当一个新的监听器上线,或者一个现有的监听器想要一个完整的重放时,它会先读取S3以便赶上。

我目前的项目是一个多租户场景,我在Postgres上推出了自己的项目。像Citus这样的东西似乎适合于可扩展性,可以通过tentant + stream进行分区。

Kafka在分布式场景中仍然非常有用。将每个服务的事件暴露给其他服务是一个非常重要的问题。事件存储不是为此而构建的,但这正是Kafka所做的。每个服务都有自己的内部事实来源(可能是事件存储或其他),但是听听Kafka知道“外部”发生了什么。该服务还可以向Kafka发布事件,以通知服务所做的有趣事情的“外部”。


14
投票

您可以使用Kafka作为事件存储,但我不建议这样做,尽管它可能看起来不错:

  • Kafka仅保证至少一次交付,并且事件存储中存在无法删除的重复项。更新:在这里,您可以阅读为什么Kafka如此难以及有关如何最终实现此行为的最新消息:https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how-apache-kafka-does-it/
  • 由于不变性,当应用程序发展并且需要转换事件时,没有办法操纵事件存储(当然有像upcasting这样的方法,但是......)。一旦可能会说你永远不需要转换事件,但这不是正确的假设,可能会有你原始备份的情况,但你将它们升级到最新版本。这是事件驱动架构中的有效要求。
  • 没有地方可以持久保存实体/聚合的快照并且重放将变得越来越慢。从长远角度来看,创建快照是事件存储的必备功能。
  • 鉴于Kafka分区是分布式的,并且与数据库相比,它们很难管理和备份。数据库简单易懂:-)

所以,在你做出选择之前,你要三思而后行。事件存储作为应用程序层接口(监视和管理),SQL / NoSQL存储和Kafka作为代理的组合是比Kafka处理这两个角色以创建完整功能完整解决方案更好的选择。

事件存储是一项复杂的服务,如果您认真考虑在事件驱动架构中应用事件源,CQRS,Sagas和其他模式并保持高性能,则需要更多Kafka所能提供的服务。

随意挑战我的答案!您可能不喜欢我对您最喜欢的具有大量重叠功能的经纪人所说的话,但Kafka仍然不是设计为事件存储,而是更多地作为高性能代理和缓冲区同时处理快速生产者与慢速消费者场景,例如。

请查看eventuate.io微服务开源框架,以发现有关潜在问题的更多信息:http://eventuate.io/

自2018年2月8日起更新

我没有收录评论中的新信息,但同意其中的一些方面。此更新更多是关于微服务事件驱动平台的一些建议。如果您认真对待微服务稳健设计和最高性能,我将为您提供一些您可能感兴趣的提示。

  1. 不要使用Spring - 它很棒(我自己经常使用它),但同时又重又慢。它根本不是微服务平台。它只是一个框架来帮助你实现一个(这背后的很多工作......)。其他框架“只是”轻量级REST或JPA或不同的框架。我推荐可能是一流的开源完整微服务平台,它可以回归纯Java根源:https://github.com/networknt

如果您对性能有疑问,可以将自己与现有的基准测试套件进行比较。 https://github.com/networknt/microservices-framework-benchmark

  1. 根本不要使用Kafka :-))这是半开玩笑。我的意思是,虽然卡夫卡很棒,但它是另一个以经纪人为中心的系统。我认为未来是在无需经纪人的邮件系统中。你可能会感到惊讶,但有比Kafka系统更快的速度:-),当然你必须降到更低的水平。看看纪事。
  2. 对于事件存储,我建议使用名为TimescaleDB的高级Postgresql扩展,它专注于大容量的高性能时间序列数据处理(事件是时间序列)。当然CQRS,事件采购(重放等功能)都是在light4j框架中构建的,它使用Postgres作为低存储空间。
  3. 对于消息传递,请尝试查看Chronicle Queue,Map,Engine,Network。我的意思是摆脱这种老式的经纪人中心解决方案,并采用微信息系统(嵌入式系统)。 Chronicle Queue实际上比Kafka更快。但我同意这不是一个解决方案,你需要做一些开发,否则你去购买企业版(付费一个)。最后,通过消除维护Kafka集群的负担,将从Chronicle构建您自己的消息传递层。

6
投票

是的,您可以将Kafka用作活动商店。它运作得很好,尤其是引入了Kafka Streams,它提供了一种Kafka本地方式来处理你的事件到累积的state that you can query

关于:

能够重放事件日志,允许新订户在事后注册系统。

这可能很棘手。我在这里详细介绍了:https://stackoverflow.com/a/48482974/741970

© www.soinside.com 2019 - 2024. All rights reserved.