关于CQRS(Command Query Responsibility Segration)架构,简单的说,就是一个系统,从架构上把它拆分为两部分:命令处理(写请求)+查询处理(读请求)。然后读写两边可以用不同的架构实现,以实现CQ两端(即Command Side,简称C端;Query Side,简称Q端)的分别优化。CQRS作为一个读写分离思想的架构,在数据存储方面,没有做过多的约束。
命令 (Command)
业务逻辑大部分都发生在写入的时候,例如用户购买商品提交订单时,我们要验证库存,用户信息订单数据是否有效等。如果从传统DDD的角度看,Command类似于Application Service,用户的命令(如提交订单)会以Command的形式得到执行,而Command中也不会带有业务逻辑,Command中做的事情基本上是:通过Repository得到相关的领域对象,调用某些领域服务(Domain Service)执行一些操作(业务逻辑都将保留在领域模型中),然后执行Commit或SaveChanges之类的方法提交改动,之后,相关的数据就会写入到Write DB中(图的DB,下文统称Write DB)。需要注意的是,UI上的查询都是查Read DB,而不是Write DB。
领域模型 (Domain Model)
DDD中说的领域模型没有太多区别,是“the heart of software”。
所有的业务逻辑都只在Domain Model中处理。
领域事件 (Domain Event)
发生在一个特定领域中的事件,是你希望在同一个领域中其他部分知道并产生后续动作的事件。但是并不是所有发生过的事情都可以成为领域事件。一个领域事件必须对业务有价值,有助于形成完整的业务闭环,也即一个领域事件将导致进一步的业务操作。
聚合根(Aggregate Root):一个Bounded Context(界定的上下文)可能包含多个聚合,每个聚合都有一个根实体,叫做聚合根;
CQRS架构的优点
- CQ两端架构分离、相互不受束缚,各自独立设计、扩展
- C端通常结合DDD,解决复杂的业务逻辑;Q端轻量级查询,多种不同的查询视图通过订阅事件来更新
- C端通过分布式消息队列水平扩展,天然支持削峰
- EDA架构,整个系统各个部分松耦合,可扩展性好
- 架构层面做到无并发,实现Command的高吞吐
- 技术架构和业务代码完全分离,程序员不用关心技术问题
- 更方便的分工合作
CQRS架构的缺点
- 不是强一致性,而是面向最终一致性
- 强依赖高性能可靠的分布式消息队列
- 必须有强大可靠的CQRS框架,从头做起成本高、风险大
- 必须结合Event Sourcing模式,否则CQ分离意义不大
- Event Sourcing模式的缺点
- 一些CQRS的最佳原则提高了开发人员的门槛