-
浅谈CQRS
大背景
- 基于事件驱动的微服务架构
在微服务的大背景下,服务拆分、服务通信、服务事务管理成为需要解决和研究的课题。服务的查询是其中一个,服务拆分后,联合查询
成为一大问题。
为什么
服务拆分后的通常查询措施
- API组合模式
检索多个服务所拥有的数据,通过调用拥有数据的服务并组合结果来实现查询操作
(大白话:哪个表/库/服务有我想要的数据,就调用那个表/库/服务的查询接口,拿到数据后通过编写代码将其组合成业务所需数据)
在单体应用中,当联合查询不足以满足业务数据需求的时候,也会用到这种模式。在微服务中没有了“跨库联合查询”,将API组合模式
搬过来就显得“理所当然”了
组合的开销成本
数据组合需要调用多个服务,网络、数据集操作等多因素造成的开销大大增加查询的耗时。这时候spring reactive stack
就排上了一定用用场,将编程模式从同步转到异步。
组合的职责问题
服务拆分后,各服务职责单一
几乎已经成为“政治正确”,但是往往查询并不是单个服务的查询,而是queryXxxDetail()
这样多服务的数据整合。
API Gateway
,严格来讲并不是所谓的API组合模式
,从结果来看确实是组合
了API
,但它却将组合
的操作下放到了service
,使service
不再“纯粹”。组合的数据一致性
查询数据一致性
通过组合API模式
查询的服务间缺少事务支持,进行多数据库查询会出现部分数据不一致的情况。虽然办法总比困难多,但这不是写业务的程序员应该考虑的事情,也不应该徒增代码的复杂度。
是什么
什么是CQRS(命令查询职责隔离)
理解概念就先了解定义CQRS(Command Query Responsibility Segregation)
有四个字母,分开说
C和Q
C和Q的具体
- Pressing a command button is a way to make the machine change state.but you can press a query button. This does not change the state.
C和Q的抽象
- A command (procedure) does something but does not return a result.
- A query (function or attribute) returns a result but does not change the state.
这里command
翻译成指令或许更好理解一点,综上就是:
command
:改变状态,但不返回结果query
:返回结果,但不改变状态
然后放在应用程序里,对应过来就是CUD
和R
。(当然会有改变状态并返回结果的,如保持实体并返回实体ID)
R&S
字面意思,就是C(Command)和Q(Query)的职责(Responsibility)隔离(Segregation),没什么需要强加的解释。
CQRS
CQRS是命令查询职责隔离( Command Query Responsibility Segregation) 的简称,顾名思义,它涉及隔离或问题的分隔。它将持久化数据模型和使用数据的模块分为两部分:命令端和查询端。命令端模块和数据模型实现创建、更新和删除操作(缩写为CUD,例如: HTTP POST、PUT和DELETE)。查询端模块和数据模型实现查询(例如HTTP GET)。查询端通过订阅命令端发布的事件,使其数据模型与命令端数据模型保持同步。
CQRS
将原本的CRUD
彻底分为CUD
和R
(类似将Elasticsearch或Solr文本搜索数据库文本搜索查询,在应用程序层面再竖切一刀),即命令端模块
和查询端模块
,同时将查询端数据库
从物理层面分开,作为视图数据库
,查询端模块
订阅命令端模块
的事件
并更新(同步)视图数据库
,至于视图数据库
用什么数据库取决于业务需求。(这就有点从数据仓库(DW)
到数据集市(DM)
的意思)
- 此处
视图数据库(view database)
并非数据库视图(database view)
视图数据库(view database)
:对数据库职责的抽象
数据库视图(database view)
:对数据库数据的抽象 R
分离出来并不意味着查询模块
部分没有CUD
(数据持久化)
怎么样
- 架构隔离和可扩展性
视图数据库
并没有指定具体数据库,完全取决于业务需求,所以就可以“为所欲为”了。就算修改视图
结构也不会影响原始数据
。
- 数据查询更高效和简单
CUD
和R
分开后,一方面解决在读
与写
负载不均的情况(通常读
大于写
),R
分离出来后,视图数据库
可以自由缩放;另一方面数据整合已经在查询端模块
的事件处理程序
完成,查询和数据的获取就变得简单多了。
- 事务数据最终一致性
在视图数据库
支持事务模式的前提下,事件处理程序
持久化的数据最终是一致的。(保证事件有序)
最后
“没有一项技术可以被称为‘银弹’”。从大前提(基于事件)的部署,到如何设计CQRS视图的细节都需要考虑细致,还有团队和成本,到最终的落地。架构设计应适应业务发展,杀鸡用牛刀,杀前还得磨刀,杀完把鸡扔了,却只取了个鸡蛋,那就舍本求末乱套了。
参考
- Bertrand Meyer.Object-Oriented Software Construction 2nd Edition[M].Prentice Hall,1997:751
- Bertrand Meyer. Eiffel: a language for software engineering,2014:24
- Chris Richardson.Microservice Patterns[M].Manning Publications,2019:229
- (美)克里斯·理查森(Chris Richardson),喻勇.微服务架构设计模式[M].机械工业出版社,2019.4:212-243
版权属于:羽子
本文链接:https://reki.me/studying/cqrs.html
本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
允许自由转载和修改,但请务必标明文章来源且不得运用于商业目的并以相同方式分享。