CQRS 和 Event Sourcing 的区别

2025年3月7日 | 阅读6分钟

事件溯源 是一种编程方式,它似乎为回应上述声明提供了希望,但也存在技术世界混乱的现状。其次,事件溯源可能不像其他数据处理方式那样广为人知,但它有一种可以极大地丰富系统的视角。

CQRS 代表命令查询职责分离(Command Question Duty Segregation),它是一种设计模式,用于分离系统中数据的读写职责。在全球 CQRS 软件设计中,这种形状分为几个组件。第一部分用于更新和删除(写版本)。第二部分是读取,查询模型只负责读取。CQRS 的工作方式与传统的 CRUD 方法(只使用单个数据库)大不相同,相反,CQRS 将使用两个 数据库,或者至少是分开的表。双方都设计用于读写运动数据。CQRS 可以与事件溯源结合使用来解决问题。在这种架构中,通过命令触发的事件将被记录在事件存储中。当事件被转换为适合模型时,它们会被发布到一个单独的查询数据存储中。这种方法在解决 CQRS 引起的一些可伸缩性问题方面特别有趣。因此,本文旨在讨论 CQRS 与事件溯源的区别。但是,在争论是什么区分了这两个概念之前,我们应该回顾一下 CQRS 和事件溯源的优缺点。

什么是事件溯源?

CQRS 通常不与事件溯源配对,而事件溯源经常与 CQRS 一起使用。尽管这两种方式都有美好的目标和功能,但它们可以很好地互补。在事件溯源中,机器信息的*.main*文件被保存为捕获事件并调整其状态的事件日志。在 CQRS 的情况下,一个事件溯源的数据库结构由所有成功完成的命令的按时间顺序排列的存储库组成。

与主要在其数据库中保存命令效果记录的系统相比,事件溯源的系统遵循一种不同的方法。例如,在一个传统的博客平台上,数据库保存了一组文章,每次更新命令都会更改特定的条目。相反,一个事件溯源的系统存储了一个名为“文章活动”的表,该表记录了每一个创建、修改和删除命令作为单独条目。

事件溯源的优点

事件溯源的几个优点如下:

事件溯源的主要优点之一是能够在任何给定时间通过重放从头开始尽可能多的指令来重新创建设备的状态。如果指令以某种方式准备好存储设备(带有 oldValue 和 newValue 对),我们可以随时平滑地播放和倒带命令流。

此外,我们可以对活动进行有逻辑的重处理,以生成数据的替代视图,根据*.minute*数据计算更改,或估算最多活跃发帖者的数量。

事件溯源的缺点

事件溯源的几个缺点如下:

事件溯源的缺点是,要确定设备的状态,我们需要从头开始重放事件。我们通常通过使用 CQRS 模式来生成摘要来处理这个问题。事件溯源的一个常见例子是银行账户。在一个*.real*银行系统中,一个账户不是保存在一个只有余额区域的表中的单个条目。相反,有一个记录了对该账户进行的所有*.credit*和*.debit*交易的整个银行的分类账。

什么是 CQRS?

我们了解到,事件溯源提供了一种数据存储方法,它维护事件记录,而不是依赖于会修改、访问和删除的传统表。此外,我们知道通过事件溯源检索数据需要一个额外的过程。

本质上,我们必须输入所有事件,然后采取额外的步骤来按时间顺序对其进行优化,以达到当前状态。这样,我们就可以收集我们的事件,同时转换过程确保您的应用程序逻辑以所需格式获取数据,例如购物车的*.concise*表格表示。

当事件数量很大时,这种设置会出现问题。大量的事件会减慢*.reduction*操作的速度,并消耗比预期更多的*.clock cycles*。虽然对于小型购物车来说这可能不是问题,但如果我们试图对整个银行账户历史记录应用*.chronological reduction*,例如,这可能会非常耗时。

命令查询职责分离 (CQRS) 解决了这个问题。这种方法在数据写入时执行计算,而不是在读取时执行。因此,每次计算*.only once*,无论数据*.later on*访问多少次。

命令和查询

想象一下我们有一个简单的博客应用程序,我们想要一个文章的 CRUD API。在一个纯 RESTful API 中,我们会有一个像 /api/article/ 这样的端点,我们可以在其中

  • 创建新帖子:将*.Article*对象 PUT 到 URL
  • 更新帖子:POST 一个*.Article*。
  • 读取所有文章:GET /api/article/。
  • 读取单篇文章:GET /api/article/{article id。

当我们创建一个*.writing*时,我们不应该被要求提供所有将从服务器检索到的信息。例如,创建日期或发布状态应由服务器设置,而不是由客户端设置。我们也可能无法访问*.comments*列表或*.views*数量等信息。

主要区别在于简单的 GET 请求格式与更复杂的创建或更新操作。这类似于区分查询和命令。

查询用于从设备或载体检索事实,通常是所有可用信息。命令用于修改信息,在大多数情况下,我们不希望提供所有可读信息,因为我们不拥有它,或者我们不允许修改它。

优点

  • 可伸缩性:读写模型可以独立扩展,优化写模型的一致性,优化读模型的性能。
  • 代码简化:将问题分开可以降低复杂性,使代码更*.clean*且更易于维护。
  • 数据存储的灵活性:可以根据需要为命令(写)和查询(读)使用不同的数据库(例如,写用关系型,读用 NoSQL)。
  • 安全性:命令和查询的*.separate*授权可以提高安全性。

CQRS 和事件溯源之间的主要区别

CQRS 和事件溯源之间有几个主要区别。一些主要区别如下:

特点CQRS (命令查询职责分离)事件溯源
定义一种将读(查询)和写(命令)操作分开的设计模式。一种将更改(事件)存储为一系列事件而不是最终状态的模式。
目的通过分离命令(写)和查询(读)模型来优化系统性能。将系统状态存储为一系列事件,并通过重放这些事件来派生状态。
数据处理它使用两个不同的模型:一个用于写入(命令模型),一个用于读取(查询模型)。它将系统中的每一次更改记录为一个事件,从而可以在任何时间点重建状态。
状态表示将数据的当前状态存储在数据库中(通常为命令和查询分开)。它存储发生的事件(状态更改)的*.series*,而不是直接存储当前状态。
典型的存储机制为读写模型使用单独的数据库或表(例如,读用 NoSQL,写用关系型)。一个事件日志,用于跟踪所有事件。事件按时间顺序存储。
事件历史CQRS 本身不存储事件历史,但可以与事件溯源结合使用来处理它。它维护所有事件(更改)的完整历史记录,允许系统“重放”到任何*.point*。
系统状态命令更新状态,查询读取当前状态,通常对每个状态都有不同的优化。通过重放事件日志中的事件来重建状态。
性能影响分离读写,允许每个*.independently*扩展并针对其自身的需求进行优化。重放事件以计算当前状态可能*.resource-intensive*,除非进行快照等优化。