CQRS代表Command Query Responsibility Segregation(命令查询职责分离)
。它的核心思想是,您可以使用不同的模型来更新信息,而不是使用您用来读取信息的模型。在某些情况下,这种分离是有价值的,但是要注意,对于大多数系统CQRS会增加风险的复杂性。
人们用于与信息系统交互的主流方法是将其视为CRUD数据存储。我的意思是,我们有一些记录结构的构思模型,我们可以创建新的记录,读取记录,更新已有的记录,并在我们完成这些记录时删除记录。在最简单的情况下,我们的交互都是关于存储和检索这些记录的。
随着我们的需求变得更加复杂,我们逐渐远离这种模式。我们可能希望以不同于记录存储的方式查看信息,可能会将多个记录合并为一个记录,或者通过组合不同位置的信息来形成虚拟记录。在更新方面,我们可能会发现验证规则,只允许存储特定的数据组合,或者甚至可能推断要存储的数据与我们提供的数据不同。

当这发生时,我们开始看到信息的多重表示。当用户与信息进行交互时,他们会使用各种各样的信息,每种信息都是不同的表示形式。开发人员通常会构建自己的概念模型,用它来操纵模型的核心元素。如果你使用的是域模型,那么这通常是域的概念表示。您通常也会将持久性存储尽可能地接近概念模型。
这种多层表示的结构可能会变得非常复杂,但是当人们这样做时,他们仍然将其解析为单一的概念表示,这充当了所有表示之间的概念集成点。
CQRS引入的变化是将该概念模型分解为独立的更新和显示模型,分别称为Command和Query,遵循CommandQuerySeparation的词汇表。其基本原理是,对于许多问题,特别是在更复杂的领域中,对于命令和查询拥有相同的概念模型,会导致一个更复杂的模型,但这两者都不太好。
通过单独的模型,我们通常意味着不同的对象模型,可能运行在不同的逻辑过程中,可能在不同的硬件上。Web示例将会看到用户正在查看使用查询模型呈现的网页。如果他们发起更改,将更改发送到单独的命令模型进行处理,则生成的更改将传递给查询模型以呈现更新后的状态。
这里有相当大的变化空间。内存中的模型可以共享相同的数据库,在这种情况下,数据库充当两个模型之间的通信。但是,它们也可能使用单独的数据库,从而有效地将查询端的数据库变为实时ReportingDatabase。在这种情况下,需要在两个模型或其数据库之间建立一些通信机制。
这两个模型可能不是单独的对象模型,可能是相同的对象在其命令端和其查询端具有不同的接口,而与关系数据库中的视图相似。但通常当我听说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是一种很好的模式,但要注意,它很难使用,如果你处理不当,你可以很容易地砍掉重要的部分。