CQRS和事件溯源的区别

43
CQRS(命令查询责任分离)和事件溯源有什么区别?
我认为事件溯源是CQRS的一种类型。它们之间的区别在哪里?什么使得事件溯源与其他类型的CQRS不同?
谢谢。
5个回答

58

CQRS

CQRS是由Greg Young引入的; 他在2010年的解释

CQRS只是在原本只有一个对象的情况下创建了两个对象。这种分离是基于方法是命令还是查询(与Meyer在命令和查询分离中使用的相同定义,命令是任何改变状态的方法,查询是任何返回值的方法)。

通常情况下,这意味着每个对象将使用不同的数据表示形式,以适应其目的。在这里,通常使用的术语是“写模型”和“读模型”。通常情况下,首先对写模型进行更改,然后异步传播到读模型。

事实上,“2”这个数字并没有什么神奇之处;你也可以有3个不同的表示形式,就像有两个一样。

这里的关键好处是您可以独立地调整数据结构以适应读取用例和写入用例。

事件溯源

事件溯源是一种以非破坏性方式记录状态的模式。每次状态变化都会被追加到日志中。由于这些变化是非破坏性的,我们保留了在对象生命周期的任何时刻回答关于对象状态的查询的能力。
使用事件可以更有效地利用存储空间(相对于在每次变化后存储完整状态的表示),同时保留变化的语义意图(相对于仅存储差异)。
Greg这样描述事件溯源:
将当前状态存储为一系列事件,并通过重放这一系列事件在系统内重新构建状态。
CQRS + 事件溯源
这些技术经常被一起使用,因为作为一个概念性数据结构,日志在支持查询方面并不特别高效。通常,您会希望将日志压缩成其他更适合读取的表示形式(读取很可能比写入频繁得多)。
因此,在CQRS模式中,我们通常使用日志作为持久化模型,然后从该日志中创建适合的对象查询表示,并缓存这些表示,以便快速支持查询(接受查询中使用的表示可能不总是反映最新可用信息的妥协)。

44

让我们举一个简单的现实世界的例子:

CQRS: 我们将使用缓存/Redis/Elasticsearch来进行读取查询,使用数据库/MySQL/Mongo来进行写入查询。这就是CQRS的精髓。将读取和写入逻辑分离就是CQRS。

事件溯源: 所有我们使用的发布/订阅模式都属于事件溯源。在这里,我们将消息作为一个事件发布到队列(Kafka/RabbitMQ),而订阅者只需通过订阅这些队列来消费这些消息。

CQRS + 事件溯源: 让我们仍然使用上面的例子。 当任何更新到写入模型(数据库/MySQL/Mongo)中时,我们应该如何更新读取模型(缓存/Redis/Elasticsearch)呢?

我们可以在这里使用事件溯源。每当有任何更新到数据库中时,会创建一个包含更改内容的事件,并将该事件推送到队列中。现在,阅读器模型(Elasticsearch)将订阅这些队列并在其状态之上应用这些事件。因此,我们始终保持了读取和写入模型之间的相同状态。


2
简单明了的解释,感谢@lokanadham100 - Surya

10

CQRS:

CQRS代表命令查询职责分离。由Greg Young引入。每个方法都应该是执行操作的命令或返回数据的查询。命令不能返回数据,查询不能更改数据。每个模型都可以针对特定上下文进行优化,并保持其概念完整性。

事件溯源:

事件溯源不是CQRS所必需的。您可以将事件溯源和CQRS结合使用。这种组合可能会带领我们走向一种新类型的CQRS。它涉及将应用程序所做的状态更改建模为不可变的事件序列或日志。您可能会想到系统日志和事件日志,但说实话,事件日志并不等同于事件溯源。事件溯源强制当前状态从历史中派生。如果您无法从历史推理出当前系统状态,则没有进行事件溯源。实际上,事件是业务事实。

在域驱动设计中,事件必须遵循普遍语言,系统中的所有事件必须在过去,并以过去时命名。事件是独立的,我是指事件应具有足够的数据来描述自己。

事件溯源越来越受欢迎。因为它使故障排除更容易,并且具有更好的性能特征;写入和读取可以独立扩展。GRASP事件溯源指的是松耦合的应用程序架构。此外,它还可以在未来添加需要处理相同事件但创建不同物化视图的更多应用程序。


2
CQRS代表命令查询分离原则,它超越了CQS原则-每个方法应该是查询或命令,但不能同时存在-提出了两个分离的模型,用于写操作和读操作。
这不仅适用于应用程序级别,还适用于基础架构级别-提出了两个不同的存储系统。
事件溯源是一种持久化方法,在这种方法中,我们不是存储对象的最后状态,而是存储整个生命周期内发生在这些对象上的不同领域事件,因此我们可以在任何时间点上应用领域事件以获得任何状态。
我刚刚在我的博客上写了两篇文章,一篇关于每个概念:

0

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