CQRS- Command Query Responsibility Segregation
CQRS 代表命令查询职责分离。我第一次听到格雷格・杨(Greg Young)描述了这种模式。其核心概念是,您可以使用与用于读取信息的模型不同的模型来更新信息。对于某些情况,这种分离可能很有价值,但请注意,对于大多数系统,CQRS 会增加风险复杂性。
人们与信息系统交互的主流方法是将其视为 CRUD 数据存储。我的意思是,我们有一些记录结构的心智模型,我们可以在其中创建新记录、读取记录、更新现有记录以及在完成记录后删除记录。在最简单的情况下,我们的交互都是关于存储和检索这些记录。
随着我们的需求变得更加复杂,我们逐渐远离这种模式。
我们可能希望以与记录存储不同的方式查看信息,也许将多个记录合并为一个,或者通过组合不同位置的信息来形成虚拟记录。
在更新方面,我们可能会发现验证规则仅允许存储某些数据组合,或者甚至可能推断要存储的数据与我们提供的数据不同。
当这种情况发生时,我们开始看到信息的多种表示形式。当用户与信息交互时,他们使用该信息的各种表示形式,每种表示形式都是不同的。
开发人员通常构建自己的概念模型,用于操作模型的核心元素。如果您使用域模型,那么这通常是域的概念表示。
通常,您还可以使持久存储尽可能接近概念模型。
这种多层表示的结构可能会变得相当复杂,但是当人们这样做时,他们仍然将其分解为单个概念表示,该概念表示充当所有表示之间的概念集成点。
CQRS 引入的更改是将概念模型拆分为单独的模型以进行更新和显示,按照 CommandQuerySeparation 词汇表,将其分别称为 Command 和 Query。其基本原理是,对于许多问题,特别是在更复杂的领域,使用相同的命令和查询概念模型会导致更复杂的模型,但两者都不能很好地发挥作用。
通过单独的模型,我们通常指的是不同的对象模型,可能在不同的逻辑进程中运行,也可能在单独的硬件上运行。 Web 示例将看到用户正在查看使用查询模型呈现的网页。
如果它们发起更改,该更改将路由到单独的命令模型进行处理,所得更改将传递到查询模型以呈现更新后的状态。
这里有相当大的变化空间。内存模型可以共享相同的数据库,在这种情况下,数据库充当两个模型之间的通信。
然而,他们也可以使用单独的数据库,有效地将查询端的数据库变成实时报告数据库。在这种情况下,两个模型或其数据库之间需要某种通信机制。
这两个模型可能不是单独的对象模型,可能是相同的对象在其命令端和查询端具有不同的接口,就像关系数据库中的视图一样。但通常当我听说 CQRS 时,它们显然是不同的模型。
CQRS 自然地适合其他一些架构模式。
- 当我们摆脱通过 CRUD 交互的单一表示形式时,我们可以轻松地转向基于任务的 UI。
- CQRS 非常适合基于事件的编程模型。通常会看到 CQRS 系统分为与事件协作进行通信的单独服务。这使得这些服务能够轻松利用事件溯源。
- 拥有单独的模型会引发有关保持这些模型一致的难度的问题,这增加了使用最终一致性的可能性。
- 对于许多领域,更新时需要很多逻辑,因此使用 EagerReadDerivation 来简化查询端模型可能是有意义的。
- 如果写入模型为所有更新生成事件,您可以将读取模型构造为 EventPosters,允许它们成为 MemoryImages,从而避免大量数据库交互。
- CQRS 适合复杂的领域,这种领域也可以从领域驱动设计中受益。
何时使用它
与任何模式一样,CQRS 在某些地方很有用,但在其他地方则不然。许多系统确实适合 CRUD 心理模型,因此应该以这种方式完成。 CQRS 对于所有相关人员来说都是一次重大的精神飞跃,因此除非其好处值得飞跃,否则不应解决。
虽然我曾经成功使用过 CQRS,但到目前为止,我遇到的大多数情况都不是那么好,CQRS 被视为使软件系统陷入严重困难的重要力量。
特别是,CQRS 只能用于系统的特定部分(DDD 术语中的 BoundedContext),而不是整个系统。按照这种思维方式,每个限界上下文都需要自己决定如何建模。
到目前为止,我看到了两个方向的好处。首先,使用 CQRS 可能更容易解决一些复杂的领域。然而,我必须强调,这种适合 CQRS 的情况在很大程度上是少数。
通常,命令和查询端之间有足够的重叠,因此共享模型会更容易。在不匹配的域上使用 CQRS 会增加复杂性,从而降低生产力并增加风险。
另一个主要好处是处理高性能应用程序。 CQRS 允许您将负载与读取和写入分开,从而使您可以独立扩展每个负载。如果您的应用程序发现读取和写入之间存在很大差异,那么这非常方便。
即使没有,您也可以对两侧应用不同的优化策略。一个例子是使用不同的数据库访问技术进行读取和更新。
如果您的域不适合 CQRS,但您的查询要求很高,会增加复杂性或性能问题,请记住您仍然可以使用 ReportingDatabase。 CQRS 对所有查询使用单独的模型。使用报告数据库,您仍然使用主系统进行大多数查询,但将要求更高的查询转移到报告数据库。
尽管有这些好处,您在使用 CQRS 时应该非常谨慎。许多信息系统都非常符合信息库的概念,信息库的更新方式与读取方式相同,向此类系统添加 CQRS 会显着增加复杂性。
我确实见过这样的情况,即它严重拖累了生产力,给项目增加了不必要的风险,即使是在一个有能力的团队手中也是如此。
因此,虽然 CQRS 是一种很好的工具箱模式,但要注意它很难很好地使用,如果处理不当,您很容易砍掉重要的部分。
进一步阅读
- Greg Young 是我听到的第一个谈论这种方法的人 —— 这是我最喜欢的他的总结。
- Udi Dahan 是 CQRS 的另一位倡导者,他对该技术有详细的描述。
- CQRS

浙公网安备 33010602011771号