第 24 章 CQRS:一种有界上下文的架构
CQRS(命令查询职责分离)是一种简单模式,可以将其应用到有界上下文。
它将有界上下文分离成两个模型:读取模型和写入模型(也称为事务模型)。
进行分离的原始在于让一个模型可以在无损的情况下服务于单个上下文的需求。
“第25章”命令:用于处理业务用例的应用程序服务模式。讲解命令端的实现。
“第26章”查询,领域报告;讲解查询端的实现
- 为两个上下文维护单个模型的挑战
为支持报告查询,程序需要支持很多展的实现,比如分页,查询,以及自定义文本搜索等,且破坏领域的模型,其次查询的需求远大于写入端的需求。
- 用于复杂有界上下文的一种更好的架构
以下提供两个模型来分别支持不同的需求,这里的数据库是单个,不是强制的,可以选择另外的存储方式。
- 命令端:业务任务
架构的命令端关注的是领域的规则。
-
- 显式建模意图
一个命令就是一个业务任务,系统的一个用例,并且它存在于应用内部。
一个命令就是一个意图,我希望做一些事情,比如:以下顾客的意图就是,兑换礼品券;
-
- 不受展现干扰所影响的模型
页面的数据,将会由命令和查询到两个域来提供数据。
-
- 处理业务请求
一个命令处理程序会返回命令成功或失败的确认,不需要它来查询或者报告领域状态。
- 查询端:领域报告
从查询端返回的对象就是为视图特定需要而定制的简单DTO视图模型。
查询端不需要创建持久化存储的抽象,且不需要命令端的领域模型。
-
- 直接映射到数据模型的报告
可以在数据模型中为每个UI界面或者报告构建视图,这样查询端直接查询预计算好的视图即可。
-
- 从领域事件中构建的具体化视图
可以从命令所引发的领域事件中构建一个读取模型,然后可以使用这些事件来构建具体的视图。
- 对CQRS的误解
-
- CQRS很难
CQRS不会指定框架,多个数据库,或者设计模式。
它只是表明,为了更高效,应该单独处理两个上下文。
它是一种概念上的思维转换,而非需要接受的复杂模式和原则的集合。
-
- CQRS是最终一致性的
最终一致性是使用进程外更新的读取模式并且异步于事务模型更新的实践。
可以一开始将命令模型执行和读取更新放在一个事务中,只有遇到性能问题再尝试分离解决。
-
- 模型需要源自事件
使用事件溯源是同时构建读取和写入的有效方法;
但是事件溯源是确保审计追踪准确无误这个问题的解决方案。
-
- 命令应该是异步的
CQRS不会坚持以一劳永逸的方式发送命令。
对于高度协作的领域,其中会使用相当广泛的数据跟新,实用异步命令是合理的。
-
- CQRS仅适用于消息传递系统
如果在谋求应用一个最终一致性读取存储或者异步处理命令,那么适应一个消息传递系统框架是一个好处,但是会引入技术复杂性。
-
- 需要将CQRS用于领域事件
使用事件构建一个具体化读取模型是保持读取和写入分离的有效方法。
- 可以扩展应用程序的模式
CQRS使得应用程序可以在大量复杂性运行良好。
分离读取和写入,他们的存储方式也可以不一样。
写入端,可以使用聚合保存的文档,键值对存户。
读取端可以使用关系型数据库或者缓存存储。
任何的选择和取舍,不仅仅是一个技术的决策,你的热河取舍都会影响到用户体验,并且会影响你的业务。
-
- 扩展读取端:一个最终一致的读取模型
如果一个用程序读取端的需求远远大于写入端,那么最终一致性的读取模型可以让你能够提高程序的可靠性和性能。
- 对用户体验的影响
最终一致性对用户体验的影响。
问题:基于一个过时的数据产生报告,多大程度影响决策。
- 使用读取模型合并多个有界上下文
可以使用一个读取模型在你的企业范围内合并视图,以便简化报告呈现。
- 使用报告数据库或缓存层
将事务数据库的副本通过日志等方式将数据复制到报告数据库中。
-
- 扩展写入端:使用异步命令
如果有一个高度协作式的领域,其中许多用户都会对相同实体进行变更,那么在进程处理业务任务就可以扩展应用程序以便处理高负载。
- 命令验证
- 对用户体验的影响
需要告知当前状态是接收成功,而非处理成功。
-
- 对一切进行扩展
读写的数据量都比较大。
- 要点汇总