CQRS 和事件溯源的区别

CQRS and Event Sourcing Difference

CQRS(命令查询责任分离)和事件溯源有什么区别?

我认为事件溯源是一种 CQRS。两者有何区别,事件溯源与其他类型的 CQRS 有何不同?

谢谢,

CQRS

CQRS 由 Greg Young 介绍; his explanation in 2010

CQRS is simply the creation of two objects where there was previously only one. The separation occurs based upon whether the methods are a command or a query (the same definition that is used by Meyer in Command and Query Separation, a command is any method that mutates state and a query is any method that returns a value).

通常,这意味着每个对象都将使用不同的数据表示形式,以符合目的。这里的通用语言是指一个"write model"和一个"read model"。通常情况下,首先对写入模型进行更改,然后异步传播到读取模型。

碰巧,数字“2”并没有什么神奇之处;你可以像拥有两个一样轻松地拥有 3 种不同的表示形式。

这里的主要好处是您可以独立调整读取用例和写入用例的数据结构。

事件溯源

事件源模式以非破坏性 方式记录状态。每一次状态变化都是appended to a log。因为更改是非破坏性的,所以我们保留了在对象生命周期的任何时候回答有关对象状态的查询的能力。

使用事件可以更有效地利用存储 space(相对于在每次更改后存储状态的完整表示)同时保留更改的语义意图(相对于仅存储差异)

Greg 是这样描述事件溯源的

storing current state as a series of events and rebuilding state within the system by replaying that series of events

CQRS + 事件溯源

这些技术经常配对在一起,因为日志作为一种概念数据结构,在支持查询方面并不是特别有效。您通常希望将日志压缩为更适合读取的其他表示形式(这可能比写入更频繁)。

因此,在 CQRS 模式中,我们通常使用日志作为持久化模型,然后从该日志创建查询对象的合适表示,并缓存这些表示以便快速支持查询(接受妥协查询中使用的表示并不总是反映可用的绝对最新信息)。

CQRS:

CQRS 代表命令查询责任分离。由格雷格·杨介绍。每个方法都应该是执行操作的命令或 returns 数据的查询。命令不能 return 数据,查询不能更改数据。每个模型都可以针对特定上下文进行优化,并且还保留其概念完整性。

事件溯源:

CQRS 不需要事件溯源。您可以结合使用事件溯源和 CQRS。这种组合可以将我们引向一种新型的 CQRS。它涉及将应用程序所做的状态更改建模为不可变序列或事件日志。您可能会考虑登录系统和事件日志记录,但说实话,事件日志记录不是事件溯源。事件溯源强制当前状态从历史中派生。如果您不能从历史中推断出您当前的系统,那么您就没有进行事件溯源。事实上,事件是商业事实。

在领域驱动设计中,事件必须遵循无处不在的语言,并且系统中的所有事件都必须是过去的,并且以过去时命名。事件是独立的,我的意思是事件应该有足够的数据来描述它们自己。

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

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

CQRS: 我们将使用 cache/redis/elasticsearch 进行读取查询,使用 database/mysql/mongo 进行写入查询。这正是 CQRS。分离读写逻辑是CQRS。

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

CQRS + 事件源: 让我们仅以上面的示例为例。 当写入模型(database/mysql/mongo)有任何更新时,我们应该如何更新读取模型(cache/redis/elasticsearch)?

我们可以在这里使用事件源。每当对数据库进行任何更新时,都会创建一个事件(包含更改)并将该事件推送到队列中。现在 Reader Model(elasticsearch) 将订阅这些队列并在其状态之上应用事件。因此,我们在读写模型中保持了相同的状态。

CQRS 代表命令查询隔离原则并超越了 CQS 原则 - 每个方法应该是查询或命令,但不能同时是 - 为写入和读取操作提出了两个分离的模型。

这不仅是在应用层面,也是在基础设施层面——提出两种不同的存储系统。

事件溯源是一种持久化方法,我们不存储对象的最后状态,而是存储该对象在其整个生命周期中发生的不同域事件,因此我们可以在任何时间点进入任何状态按顺序应用域事件。

我刚刚在我的博客上写了两篇文章,一篇关于每个概念: