在微服务中应用简化的 CQRS 和 DDD 模式
CQRS is an architectural pattern that separates the models for reading and writing data. The related term Command Query Separation (CQS) was originally defined by Bertrand Meyer in his book Object-Oriented Software Construction. The basic idea is that you can divide a system's operations into two sharply separated categories:
CQRS(命令查询职责分离)是一种将读取和写入数据模型分离开来的架构模式。与之相关的术语 CQS(命令查询分离)最初由 Bertrand Meyer 在他的著作《面向对象软件构造》中提出。其基本思想是,你可以将系统的操作清晰地划分为两个截然不同的类别:
-
Queries. These queries return a result and don't change the state of the system, and they're free of side effects.
查询(Queries):这些查询会返回结果,但不会改变系统的状态,并且没有任何副作用。
-
Commands. These commands change the state of a system.
命令(Commands):这些命令会改变系统的状态。
CQS is a simple concept: it is about methods within the same object being either queries or commands. Each method either returns state or mutates state, but not both. Even a single repository pattern object can comply with CQS. CQS can be considered a foundational principle for CQRS.
CQS 是一个简单的概念:它关注的是同一个对象内的方法要么是查询,要么是命令。每个方法要么返回状态,要么修改状态,但不能两者兼得。即使是单个仓储模式(Repository Pattern)的对象也可以遵循 CQS。可以说,CQS 是 CQRS 的基石。
Command and Query Responsibility Segregation (CQRS) was introduced by Greg Young and strongly promoted by Udi Dahan and others. It's based on the CQS principle, although it's more detailed. It can be considered a pattern based on commands and events plus optionally on asynchronous messages. In many cases, CQRS is related to more advanced scenarios, like having a different physical database for reads (queries) than for writes (updates). Moreover, a more evolved CQRS system might implement Event-Sourcing (ES) for your updates database, so you would only store events in the domain model instead of storing the current-state data. However, this approach is not used in this guide. This guide uses the simplest CQRS approach, which consists of just separating the queries from the commands.
CQRS(命令查询职责分离)由 Greg Young 提出,并得到了 Udi Dahan 等人的大力推崇。它基于 CQS 原则,但在细节上更加深入。它可以被视为一种基于命令和事件(以及可选的异步消息)的模式。在许多情况下,CQRS 与更高级的场景相关,比如为读取(查询)和写入(更新)使用不同的物理数据库。此外,一个更成熟的 CQRS 系统可能会为你的更新数据库实现事件溯源(Event-Sourcing, ES),这样你只需在领域模型中存储事件,而不是存储当前状态的数据。不过,本指南并未采用这种方法。本指南使用的是最简化的 CQRS 方法,即仅仅将查询与命令分离开来。
The separation aspect of CQRS is achieved by grouping query operations in one layer and commands in another layer. Each layer has its own data model (note that we say model, not necessarily a different database) and is built using its own combination of patterns and technologies. More importantly, the two layers can be within the same tier or microservice, as in the example (ordering microservice) used for this guide. Or they could be implemented on different microservices or processes so they can be optimized and scaled out separately without affecting one another.
CQRS 的“分离”是通过将查询操作归入一个层,将命令归入另一个层来实现的。每一层都有自己的数据模型(注意,这里说的是模型,不一定是不同的数据库),并使用各自的模式和技术的组合来构建。更重要的是,这两层可以位于同一个层级或微服务内部(正如本指南中使用的订购微服务示例那样)。或者,它们也可以在不同的微服务或进程中实现,以便在不相互影响的情况下进行独立优化和横向扩展。
CQRS means having two objects for a read/write operation where in other contexts there's one. There are reasons to have a denormalized reads database, which you can learn about in more advanced CQRS literature. But we aren't using that approach here, where the goal is to have more flexibility in the queries instead of limiting the queries with constraints from DDD patterns like aggregates.
CQRS 意味着在原本只有一个对象来处理读/写操作的地方,现在拥有了两个对象。使用非规范化的读取数据库是有理由的,你可以在更高级的 CQRS 文献中了解到相关内容。但在本指南中,我们并没有采用那种方法,这里的目标是让查询拥有更高的灵活性,而不是让查询受到 DDD 模式(如聚合)中仅适用于事务的约束限制。
An example of this kind of service is the ordering microservice from the eShopOnContainers reference application. This service implements a microservice based on a simplified CQRS approach. It uses a single data source or database, but two logical models plus DDD patterns for the transactional domain, as shown in Figure 7-2.
这种服务的一个典型示例就是 eShopOnContainers 参考应用程序中的订购微服务(ordering microservice)。该微服务基于简化的 CQRS 方法实现。它使用单一的数据源或数据库,但拥有两个逻辑模型,并为事务性领域采用了 DDD 模式,如图 7-2 所示。

Figure 7-2. Simplified CQRS- and DDD-based microservice
图 7-2 基于简化 CQRS 和 DDD 的微服务
The Logical "Ordering" Microservice includes its Ordering database, which can be, but doesn't have to be, the same Docker host. Having the database in the same Docker host is good for development, but not for production.
逻辑上的“订购”微服务包含了它的订购数据库,该数据库可以(但并非必须)位于同一个 Docker 主机上。将数据库放在同一个 Docker 主机上有利于开发,但不适合生产环境。
The application layer can be the Web API itself. The important design aspect here is that the microservice has split the queries and ViewModels (data models especially created for the client applications) from the commands, domain model, and transactions following the CQRS pattern. This approach keeps the queries independent from restrictions and constraints coming from DDD patterns that only make sense for transactions and updates, as explained in later sections.
应用层可以是 Web API 本身。这里重要的设计要点在于,该微服务遵循 CQRS 模式,将查询和视图模型(专门为客户端应用程序创建的数据模型)与命令、领域模型以及事务分离开来。这种方法使得查询能够独立于 DDD 模式的限制和约束,而这些限制和约束仅对事务和更新有意义(这将在后续章节中解释)。

浙公网安备 33010602011771号