使用Kafka作为(CQRS)事件存储,是个好主意吗?

318

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

Kafka 支持的主要功能之一:

  • 事件捕获/存储,当然全部都是高可用的。
  • 发布/订阅体系结构
  • 能够重放事件日志,这使得新的订阅者在事后注册系统成为可能。

诚然,我并不完全了解 CQRS / 事件源,但这似乎非常接近事件存储应该具备的功能。有趣的是:我真的找不到关于 Kafka 作为事件存储使用的太多信息,所以也许我错过了什么。

那么,Kafka 是否还缺少一些东西才能成为一个好的事件存储?它会起作用吗?使用其生产环境?有兴趣了解见解、链接等。

基本上,系统的状态是基于系统曾经接收过的事务/事件来保存的,而不仅仅是保存当前状态/系统快照,这通常是所做的。 (将其视为会计中的总分类帐:所有交易最终都加起来得出最终状态)。 这可以实现各种酷炫的功能,但只需阅读提供的链接即可了解更多信息。

嗨,Geert-Jan。回顾一下,你是如何解决这个问题的?我有一个相关的问题(在这里公开:https://dev59.com/67fna4cB1Zd3GeqPrl8W)。大多数建议采用Kafka的人似乎依赖于追加日志不可变性、高吞吐量和分区顺序保证等方面。我看到与主题内快速搜索(用于实体“重构”)、没有事务原子性和跨分区无序等问题有关(100%顺序保证意味着仅使用1个分区-杀死并发)。 - tony _008
最后我没有继续追求它,因为我结束了那个副业项目。所以恐怕没有明确的答案。 - Geert-Jan
7个回答

356

我是Kafka的原始作者之一。Kafka非常适合作为事件溯源的记录。它具有容错性,可扩展到巨大的数据大小,并具有内置的分区模型。

我们在LinkedIn上使用它来实现此形式的几个用例。例如,我们的开源流处理系统Apache Samza带有内置支持事件溯源

我认为你很少听到关于将Kafka用于事件溯源的用例,主要是因为事件溯源术语在Kafka最受欢迎的消费者网络空间似乎并不普遍。

我在这里写了一些关于这种Kafka使用方式的内容.


8
@Jay: 由于我对这个主题重新产生了兴趣,你能否详细说明一下 Kafka 似乎 被设计成在一段时间后使其发布的消息过期?如果将 Kafka 用作事件源,则应该无限期存储消息。虽然它可能是可配置的,但这会带来问题吗? - Geert-Jan
3
kafka和eventstore有什么比较吗?具体来说,我喜欢eventstore中称为Projections的FRP焦点。Kafka/Samza中是否有类似的功能? - CMCDragonkai
6
我也对@Geert-Jan向Jay提出的问题很感兴趣。由于需要每个领域聚合(想象成数百万个)的事件流(主题),因此Kafka不适用于实际事件溯源事务侧。 但是,它非常适合从GetEventStore等地方接收事件。 但是,这仅在事件无限保留的情况下才有效(对我们来说),除了一些简短的评论外,似乎Kafka并不支持这种用例?我在这里搞错了吗?例如,Samza假定只有两种情况:基于时间的保留或基于关键字的保留。还有其他情况。 - Stephen Drew
2
事件溯源要求日志条目有序。据我所知,Kafka不支持跨分区的消息排序,而分区是扩展主题的方法。那么,在基于Kafka的事件溯源系统中,如何处理消息排序以及由分区扩展的事件日志最好呢? - Jacek Obarymski
4
假设我们希望将Kafka用作事件溯源系统的存储,那么乐观锁定/并发应该如何实现? - Krzysztof Branicki
显示剩余12条评论

162

Kafka旨在成为一个消息系统,与事件存储有许多相似之处,但引用它们的介绍:

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

因此,虽然消息可能会被无限期地保留,但预期它们将被删除。这并不意味着您不能将其用作事件存储,但最好使用其他东西。查看EventStoreDB以获取替代方案。

更新

Kafka文档

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

更新2

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


20
我正在研究卡夫卡,但还有一个问题:我没有注意到任何关于乐观并发的内容。理想情况下,我希望能够说:“仅当对象的最新事件仍为N时,将此事件添加为第N+1项。” - Darien
3
@Darien:我可能会选择一种设置,其中Redis通过Redis通知提供给Kafka。由于Redis允许使用Watch/multi-exec进行乐观并发控制,所以这应该可行。 - Geert-Jan
3
@Darien 我不是事件溯源方面的专家,但我理解通常情况下你不需要使用乐观并发控制,因为事件的定义就是对已经历史发生过的事情进行记录。 - John
5
我认为,如果您已经有了一组非冲突事件的权威排序,那么这意味着它们所在的地方就是您实际的事件存储技术,而Kafka仅被用作分发它们的辅助系统。 - Darien
3
这里还有有价值的信息:https://groups.google.com/forum/#!topic/dddcqrs/rm02iCfffUY。 - manuc66
显示剩余9条评论

116

我一直在关注这个问题。但我发现现有的答案不够细致,所以我添加了这个。

简而言之,取决于您的事件溯源用法。

据我所知,有两种主要类型的事件溯源系统。

下游事件处理器 = 是

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

在这种情况下,可以理解为什么Kafka的人们正在将其推广为事件溯源解决方案。因为它与例如点击流中已经使用的方式非常相似。但是,使用术语“事件溯源”(而不是流处理)的人们可能指的是第二种用法...

应用程序控制的真相来源 = 否

这种应用程序声明自己的事件是由用户请求通过业务逻辑产生的结果。Kafka在这种情况下不起作用,有两个主要原因。

实体隔离的缺乏

这种情况需要能够为特定实体加载事件流。这样做在Kafka中是不切实际的。使用每个实体的主题可以允许此操作,但是当可能存在数千或数百万个实体时,这是行不通的。这是由于Kafka / Zookeeper的技术限制造成的。

使用短暂的写入模型的主要原因之一是使业务逻辑更改变得便宜且易于部署。

对于Kafka,建议使用按类型分主题,但这将要求为该类型的每个实体加载事件,以获取单个实体的事件。由于您无法通过日志位置确定哪些事件属于哪个实体,即使使用快照从已知的日志位置开始,如果需要结构更改来支持逻辑更改,则需要处理大量事件。

缺乏冲突检测

其次,用户可以创建竞争条件,因为对同一实体进行并发请求。保存冲突事件并在事后解决可能是非常不希望的。因此,重要的是能够防止冲突事件。为了扩展请求负载,通常会使用无状态服务,同时使用条件写入(仅在上一个实体事件为#x时才写入)。也称为乐观并发。Kafka不支持乐观并发。即使它在主题级别支持它,它也需要一直到实体级别才能有效。为了使用Kafka并防止冲突事件,您需要在应用程序级别使用有状态的序列化编写器(每个“ shard”或Kafka等效项)。这是一个重要的架构要求/限制。

主要原因:适合问题

添加于2021/09/29

Kafka旨在解决大规模数据问题。应用程序控制的真相来源是一个小规模、深入的解决方案。有效使用事件源需要制定与业务流程匹配的事件和流。这通常比通常对于大规模消费者有用的细节级别要高得多。考虑一下,如果您的银行对每个银行内部交易过程的每个步骤都有一个条目,那会怎样。在确认到您的账户之前,单笔存款或提款可能会有很多条目。银行需要这种详细级别来处理交易。但对于您来说,它大多是晦涩难懂的银行术语(领域特定语言),无法用于调整您的账户。相反,银行为消费者发布单独的事件。这些是每个完成的交易的粗略摘要。这些摘要事件是消费者在其银行对账单上所知道的“交易”。
当我像OP一样问自己同样的问题时,我想知道Kafka是否是事件源缩放选项。但也许更好的问题是,我的事件源解决方案是否有意义在大规模运作。我不能谈论每种情况,但我认为通常不是这样。当这种规模进入图片时,就像银行对账单的例子一样,事件的粒度往往是不同的。我的事件源系统应该向Kafka集群发布粗略的事件以供大规模消费者使用,而不是将其用作内部存储。

对于事件溯源,仍然需要进行扩展。策略取决于原因。通常,事件流具有“完成”或“不再有用”的状态。如果事件大小/数量成为问题,则将这些流存档是一个好答案。分片是另一个选择——非常适合区域或租户隔离的场景。在较少隔离的情况下,当流以可以跨越分片边界的方式任意相关联时,分片仍然是移动(按流ID进行分区)。但是,在流之间没有排序保证,这可能会使事件消费者的工作更加困难。例如,消费者可能会在接收描述所涉及帐户的事件之前接收交易事件。第一反应是“只使用时间戳”来排序接收到的事件。但是仍然无法保证完美发生顺序。太多不可控因素。网络故障、时钟漂移、宇宙射线等。理想情况下,设计消费者不需要跨流依赖。拥有临时缺失数据的策略。就像数据的渐进增强一样。如果您确实需要数据不可用而不是不完整,请使用相同的策略。但要将不完整的数据放在单独的区域或标记为不可用,直到填充所有数据为止。您也可以尝试处理每个事件,知道它可能由于缺少先决条件而失败。将失败的事件放入重试队列中,处理下一个事件,并稍后重试失败的事件。但要注意毒消息(事件)。

摘要

你能强制Kafka为应用程序控制的真相来源工作吗?如果你足够努力并且集成得足够深入,那么当然可以。但是这是一个好主意吗?不是。


根据评论更新

评论已被删除,但问题大致是:人们用什么来存储事件?

看起来大多数人会在现有数据库的基础上自己实现事件存储。对于非分布式场景,例如内部后端或独立产品,如何创建基于SQL的事件存储是有充分文档支持的。还有一些库可以用于各种不同类型的数据库。也有EventStoreDB专为此目的而构建。

在分布式场景中,我见过几种不同的实现。Jet的Panther项目使用Azure CosmosDB,利用Change Feed功能通知监听器。我听说AWS上类似的实现是使用DynamoDB和其Streams功能来通知监听器。分区键可能应该是流ID,以获得最佳数据分布(以减少过度预配的数量)。然而,在Dynamo中跨流进行完整重放是昂贵的(无论是读取还是成本方面)。因此,这个实现也设置了Dynamo Streams将事件转储到S3中。当新的监听器上线或现有的监听器想要进行完整重放时,它会首先读取S3以进行追赶。

我的当前项目是一个多租户场景,我在Postgres之上自己实现了一个类似的事件存储。像Citus这样的东西似乎适合可扩展性,按租户+流进行分区。

Kafka在分布式场景中仍然非常有用。将每个服务的关键事件暴露给其他服务是一个不容易解决的问题。事件存储通常不是为此而构建的,但这正是Kafka擅长的。每个服务都有自己的内部真相来源(可能是事件、BNF、图形等),然后侦听Kafka以了解“外部”正在发生的事情。服务向Kafka发布公共事件,以通知外界它遇到的有趣事情。


2
@Dominik 我在更新部分(第二段)提到了EventStore。我将返回并添加链接。我已经尝试过它,它的性能令人印象深刻。对于我们的小团队,目前不引入另一个数据库被认为更为重要,因此选择了Postgres(也用于视图)。未来我们可能会转向EventStore或在未来的产品中使用它。 - Kasey Speakman
2
@KaseySpeakman 主题与分区不同。一个主题有一个或多个分区。每个分区保证在任何给定时刻只有一个消费者组。将实体进行分区,以充分利用它。您不需要为每个实体创建一个主题,甚至不需要为每个实体创建一个分区。您只需要将它们分区,以确保所有针对相同实体的命令都发送到同一分区。 - Andrew Larsson
2
@AndrewLarsson 如果您不按实体进行分区,那么您将如何防止实体级别的冲突事件?既然我们已经回到并发冲突,那么也许您应该在medium上发布自己的文章,介绍您如何在生产中使用Kafka进行事件溯源(而不是流处理)。您如何通过按类型分区而无需实体级并发控制来完成它。我会阅读它,即使我不同意,我也不会在评论中恶意攻击您。 - Kasey Speakman
2
@KaseySpeakman 使用 Kafka 并不容易。但如果你已经认真考虑了 CQRS 和事件溯源,那么你已经到了无法承受采用简单方式的规模。你的并发模型直接影响着你的规模 - 不要随意选择一个。此外,HTTP 不是可靠的传输协议,而且,如果你处于那种规模,你不能花时间解决丢失和/或重复消息的问题。这一切都可以通过在客户端和命令处理器之间使用 Kafka 来解决,但是,是以复杂性为代价的。 - Andrew Larsson
1
@KaseySpeakman 我不是在理论构想,我在这方面有经验。我希望很快能够撰写一篇关于如何做到这一点的文章。虽然我想指出,所有好的架构最初都只是一个想法和假设。仅仅因为某些东西是新的或激进的,并不意味着它不正确。它可能会更加冒险,但并不无效。而大多数受人尊敬的建筑师都是通过发明激进的架构而成名的。 - Andrew Larsson
显示剩余16条评论

30

所有现有的答案似乎都相当全面,但是有一个术语问题,我想在我的回答中解决。

什么是事件溯源?

如果你看五个不同的地方,似乎会得到五个不同的答案。

然而,如果你看一下 Greg Young 在 2010 年的 论文,它从第 32 页开始很好地概括了这个想法,但它并没有包含最终的定义,所以我敢自己来阐述。

事件溯源是一种持久化状态的方式。与通过状态突变替换一个状态不同,你持久化代表该突变的事件。因此,你可以通过读取所有实体事件并按顺序应用这些状态突变来始终获取实体的当前状态。通过这样做,当前实体状态成为该实体所有事件的左折叠

什么是“好”的事件存储(数据库)?

任何持久化机制都需要执行两个基本操作:

  • 将新实体状态保存到数据库中
  • 从数据库中检索实体状态

这里是Greg谈论实体流概念的地方,每个实体都有自己的事件流,由实体ID唯一标识。当你拥有一个能够通过实体ID读取所有实体事件的数据库(读取流),使用事件溯源并不是一个难题。

正如Greg的论文在CQRS的背景下提到事件溯源,他解释了为什么这两个概念很好地结合在一起。虽然你拥有一个充满了一堆实体的原子状态变化的数据库,但跨多个实体的当前状态进行查询是一项艰巨的工作。这个问题可以通过将事务性(事件溯源)存储与报告(查询、读取)存储分离来解决,前者用作真相来源,后者用于跨多个实体查询当前系统状态和报告。查询存储不包含任何事件,它包含多个实体的“投影”状态,根据查询数据的需要组成。它不一定需要包含每个实体的快照,你可以自由选择查询模型的形状和形式,只要你能将事件投影到该模型中即可。

因此,“适当的”事件数据库需要支持我们所谓的“实时订阅”,以向查询模型传递新的(和历史的,如果需要重播)事件来进行投影。
我们也知道,在决定其允许的状态转换时,需要掌握实体状态。例如,已执行的资金转移不应再次执行。由于查询模型在定义上是陈旧的(即使只有毫秒),因此在陈旧数据上做出决策变得危险。因此,在对实体执行操作时,我们使用事务性(事件)存储中最新且完全一致的状态来重建实体状态。
有时,您还希望从数据库中删除整个实体,这意味着删除所有事件。例如,这可能是符合GDPR的要求。
那么,作为事件存储使用的数据库需要哪些属性才能使事件溯源系统正常工作?只需要几个:
  • 使用实体ID作为键,将事件附加到有序的追加日志中
  • 使用实体ID作为键,在有序序列中加载单个实体的所有事件
  • 使用实体ID作为键删除给定实体的所有事件
  • 支持实时订阅以将项目事件发送到查询模型

Kafka是什么?

Kafka是一种高度可扩展的消息代理,基于追加日志。 Kafka中的消息被生产到主题中,现在一个主题通常包含一个单一的消息类型,以便与模式注册表配合使用。主题可以是像cpu-load这样的东西,我们为许多服务器生成CPU负载的时间序列测量。

Kafka主题可以分区。分区允许您并行地生产和消费消息。消息仅在单个分区内排序,并且通常需要使用可预测的分区键,以便Kafka可以将消息分布在分区之间。

现在,让我们逐一检查:

  • 你能在Kafka中追加事件吗?是的,这被称为生产。你能用实体ID作为键来追加事件吗?不太行,因为分区键用于在分区之间分发消息,所以它只是一个分区键。另一个答案中提到的一件事是乐观并发性。如果你使用关系型数据库,你可能使用了Version列。对于NoSQL数据库,你可能使用了文档eTag。两者都允许你确保你更新的实体处于你知道的状态,并且在你的操作期间没有被改变。Kafka 不提供任何支持此类状态转换的乐观并发性的东西。
  • 你能使用实体ID作为键从Kafka主题中读取单个实体的所有事件吗?不行。由于Kafka不是数据库,在其主题上没有索引,所以检索主题中的消息的唯一方法是消费它们。
  • 你能使用实体ID作为键从Kafka中删除事件吗?不行,这是不可能的。消息只有在其保留期过期后才会从主题中删除。
  • 你能订阅Kafka主题以接收实时(和历史)事件,以便将它们投影到你的查询模型中吗?可以,因为主题被分区,所以你可以扩展你的投影以增加性能。

Kafka和Sansa(或Kafka Streams)怎么样?

将事件折叠到某种状态表示中,并异步地将此状态存储在另一个数据库中,是事件溯源的一个附带功能。我们通常称这些操作为“投影”,因为您可以以许多不同的方式将事件折叠到状态中。这是一个有用的功能,因为您可以随意构建特定于用例的查询模型,并从时间的开始或从某个时间点重新构建它们,因为您可以使用日志中的完整事件历史记录。

然而,这并不是事件溯源的全部内容,因为您可以使用队列完全相同的方式进行操作,没有人会说通过队列传递消息并在消息消费者中更新数据库记录是“事件溯源”。

其他需要考虑的事情

  • 将事件投影到持久化状态是单向操作。如果犯了错误,无法撤销,因为状态已经被持久化。您必须停止系统,重新投影所有内容,然后再次启动系统。这可能需要几个小时,甚至几周。
  • 您无法查看单个实体的历史记录,因为所有实体的事件(有可能达到数百万)都存储在一个主题中。您需要扫描整个主题才能弄清楚该实体发生了什么事情。
  • 当用户要求删除其数据时,您将无法执行此操作,而不重新调整主题之间的事件。您基本上必须提前考虑并应用相当复杂的模式,例如加密销毁,否则可能不符合当地的隐私法规。忽略这些法规最终可能会使您的公司退出市场。

那么,人们为什么还要这样做呢?

我认为很多人声称Kafka是事件源系统的良好选择的原因是他们将事件溯源和简单的发布-订阅(可以使用一个炒作词“EDA”,或事件驱动架构)混淆了起来。使用消息代理将事件传播到其他系统组件是一个已经存在几十年的模式。传统消息代理的问题在于消息一旦被消耗就会消失,因此您无法构建像查询模型这样从历史记录中构建出来的东西。另一个问题是,在投影事件时,您希望它们按照产生顺序被消耗,但传统的代理通常旨在支持竞争消费者模式,这不支持有序的消息处理。不要误解,Kafka不支持竞争消费者,它有一个限制即每个分区只能有一个或多个消费者,但不能反过来。Kafka完美地解决了排序问题和历史消息保留问题。因此,您现在可以从通过Kafka推送的事件构建查询模型。但这并不是事件溯源的原始想法所关注的,这正是我们今天所说的EDA。一旦这种分离变得清晰,我们就可以停止看到任何仅追加事件日志的声明成为事件源系统事件存储数据库的良好候选。


Kafka不适合事件溯源,因为您无法查询Kafka主题的内部。解决方案可以是使用Kafka作为写入侧,但将数据传输到Elasticsearch或Apache Solr作为读取侧。有像Akka Projections(https://doc.akka.io/docs/akka-projection/current/kafka.html)这样的框架来实现此功能。我开发了一个模块,并在以下博客中进行了说明(https://mehmetsalgar.wordpress.com/2022/04/18/a-model-driven-event-sourced-cloud-ready-application-with-akka-finite-state-machine-using-kafka-cassandra-and-elasticsearch/)。 - posthumecaver
请看此博客(https://mehmetsalgar.wordpress.com/2022/05/17/akka-projections-and-elasticearch/)。 - posthumecaver
如果你再读一遍我的回答,也许会更清楚。在领域中,你不能使用过时的数据来做决策。这样做可能会出错,而且错误会非常严重。使用Elasticsearch来保持状态的投影只会使情况变得更糟,糟糕得多。 - Alexey Zimarev

26

你可以使用 Kafka 作为事件存储,但我不建议这样做,尽管它看起来是一个不错的选择:

  • Kafka 只保证至少一次交付,因此事件存储中可能包含无法删除的重复数据。 更新: 您可以在此处阅读有关 Kafka 如何实现该行为和一些最新消息的原因:https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how-apache-kafka-does-it/
  • 由于不可变性,在应用程序演变并需要转换事件时无法操作事件存储(当然有像向上转型之类的方法,但...)。有人可能会说,您永远不需要转换事件,但这是不正确的假设,可能会出现这样的情况:您备份原始事件,但将其升级到最新版本。这是事件驱动架构中有效的要求。
  • 没有持久化实体/聚合快照的地方,回放速度会变得越来越慢。从长期来看,创建快照是事件存储的必备功能。
  • 给定 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 很棒,但它仍然是另一个以 Broker 为中心的系统。我认为未来在无 broker 的消息传递系统。您可能会感到惊讶,但有些比 Kafka 更快的系统:)当然,您必须降到更低的级别。看看 Chronicles。

  2. 对于事件存储,我推荐卓越的Postgresql扩展名TimescaleDB,其专注于大容量高性能时间序列数据处理(事件属于时间序列)。 当然,CQRS,事件源(重放等功能)内置于 light4j 框架中,后者将 Postgres 作为低级存储。

  3. 如果想要进行消息传递,可以考虑使用Chronicle Queue、Map、Engine和Network。我是说,摆脱这种老式的以代理为中心的解决方案,转而使用微型消息系统(嵌入式消息系统)。实际上,Chronicle Queue甚至比Kafka更快。但我同意它不是一个全能的解决方案,您需要进行一些开发,否则您就会购买企业版本(收费版本)。最终,从Chronicle构建自己的消息传递层所需的工作将通过去除维护Kafka集群的负担得到回报。


有趣的观点。能否详细说明一下其中几个要点?1)Kafka只保证至少传递一次,并且事件存储中存在无法删除的重复项。您似乎在暗示确切的一次性交付是可能存在的。据我所知(我对此非常确定),在分布式系统中并不存在这样的事情。2)至于您提到的第二点:经典的(事件溯源/领域驱动设计)思想认为,事件本质上是不可变的。也就是说:它们已经发生了,无法改变过去。回顾更改它们的实际用例是什么?谢谢! - Geert-Jan
  1. 消费者至少一次+幂等性。即:检查事件是否已经被处理过,如果是,则跳过。或者更好的方法是采取幂等操作。当然,这并非总是可行的。
  2. 我从未遇到需要对事件进行版本控制的情况。我总是将事件本身视为真相的来源,并包含所有我所需的信息。通过这样做,我从未遇到需要不同的事件结构和/或有关事件的数据的情况。但也许你的情况会有所不同。我很想听听在什么情况下您实际上需要更新事件。
- Geert-Jan
2
Kafka 现在支持精确一次交付。更新第一条。 - OneCricketeer
我知道了,我现在正在独立检查 :-) - kensai
但是向上转型仍然是一个问题,过去我曾需要向上转型。这完全不可能还是可能但不容易。还有其他需要注意的事项吗? - Leon Weemen
显示剩余2条评论

0

我认为你应该看一下Axon框架,以及他们对Kafka的支持。


-4

是的,Kafka在事件溯源模型中特别是CQRS方面表现良好,但是在设置主题的TTL时需要小心,并始终记住Kafka并不是为这种模型而设计的,尽管我们可以很好地使用它。


1
Kafka实际上是“为这种类型的使用而设计”的,正如在此处所述:https://www.confluent.io/blog/okay-store-data-apache-kafka/;在这篇文章中,将Kafka用作事件源的事件存储是第一个用例。他们还说纽约时报也将其用于文章数据。 - G. Kashtanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接