领域驱动设计之CQRS

1.概念

CQRS全称:Command Query Responsibility Segregation ,中文名:命令查询与职责分离

2.什么是CQRS

CQRS 将系统中的操作分为两类,即「命令」(Command) 与「查询」(Query)。命令则是对会引起数据发生变化操作的总称,即我们常说的新增,更新,删除这些操作,都是命令。而查询则和字面意思一样,即不会对数据产生变化的操作,只是按照某些条件查找数据。

CQRS 的核心思想是将这两类不同的操作进行分离,然后在两个独立的「服务」中实现。这里的「服务」一般是指两个独立部署的应用。在某些特殊情况下,也可以部署在同一个应用内的不同接口上。

Command 与 Query 对应的数据源也应该是互相独立的,即更新操作在一个数据源,而查询操作在另一个数据源上

3.CQRS架构

先看一下 CQRS 的架构图:

领域驱动设计之CQRS_第1张图片

从图上可以看到,当 command 系统完成数据更新的操作后,会通过「领域事件」的方式通知 query 系统。query 系统在接受到事件之后更新自己的数据源。所有的查询操作都通过 query 系统暴露的接口完成。

从架构图上来看,CQRS 的实现似乎并不难,许多开发者觉得无非是「增删改」一套系统一个数据库,「查询」一个系统一个数据库而已,有点类似「读写分离」,并没有什么特别的地方。但是真正要使用 CQRS 是有许多问题与细节要解决的。

4.CQRS带来的问题

事务

在原本单一进程,单一数据源的系统中,依靠关系型数据库的事务特性能够很好的保证数据的完整性。但是在 CQRS 中这一切都发生了变化。

当 command 端完成数据更新后,需要通过事件的形式通知 query 端系统,这就存在着一定的时间差,如果你的业务对于数据完整的实时性非常高,那么可能 CQRS 不一定适合你。

其次一个 command 触发的事件在 query 端可能需要更新数个数据模型,而这也是有可能失败的。一旦更新失败那么数据就会长时间的处于不一致状态,需要外部的介入。这也是在使用 CQRS 之前就需要考虑的。

从事务的角度来看 CQRS,需要面对的是问题从根本来说是个最终一致性的问题。

查询模型的设计

虽然 CQRS 为我们分离了领域模型和服务于查询功能的数据模型,但这意味着我们需要设计另一套针对查询功能的数据模型。一般比较简单的做法是按照查询功能所需的数据进行设计,即针对每一个查询接口设计一个数据视图,当收到领域事件时更新有关联的数据视图。

但是这种简单做法带来的问题就是当查询接口越来越多时就会难以管理,仍然需要按照 DDD 中划分 领域 的思路将属于一个 领域 的查询集中管理作为整个查询系统的一个上下文,或是干脆独立出来做一个微服务。所以即使引入了 CQRS,我们依然需要使用领域驱动的思路设计查询接口。

5.总结

CQRS 在 DDD 中是一种常常被提及的模式,它的用途在于将领域模型与查询功能进行分离,让一些复杂的查询摆脱领域模型的限制,以更为简单的 DTO 形式展现查询结果。同时分离了不同的数据存储结构,让开发者按照查询的功能与要求更加自由的选择数据存储引擎。

同样的,CQRS 在带来架构自由与便利的同时也不可避免的引入了额外的复杂性与技能要求,例如对于分布式事务,消息中间件的管理,数据模型的设计等等,所以在引入 CQRS 之前需要对团队能力与现有架构做仔细的分析,对短板进行必要的提升。如果现有系统逻辑较为简单,只是一些 CRUD,那么并不建议使用 CQRS。但是如果你的业务系统已经非常庞大,业务流程庞杂,逻辑繁琐,那么不妨尝试使用 CQRS 将 Command 与 Query 进行拆分,将领域模型与数据模型的边界划分的更清晰些。

你可能感兴趣的:(DDD)