CQRS (Command Query Responsibility Segregation,命令查询职责分离)
CQRS (Command Query Responsibility Segregation,命令查询职责分离)
Command Query Responsibility Segregation(CQRS,命令查询职责分离)是一种通过分离系统的读写操作来优化架构设计的模式。其核心思想是将数据修改(命令Command)和数据查询(查询Query)的责任划分到不同的模型中,从而实现更高效、灵活的系统设计。
问题
在现代微服务架构中,数据分散到不同地方是经常的事情,即:在一种事件发生的时候,其通常并不是写入到一起,通常会分散的写入不同的表单甚至不同的系统中,有时候还会产生更多后续变化,比如用户预定酒店,不仅会产生订单数据写入不同服务的数据库中,随着时间推移,订单状态还会发生修改(用户入住、退房、超时未入住等),又会产生新的写入。
问题是:在这种情况下,如何快速的从多个系统中拉取数据。按照刚才的例子就是如何快速的对用户的订单列表接口做出响应。
解决方案
专门为查询定义一个视图(view)数据库,它是专门为支持该查询或组相关查询而设计的只读 “副本” 。通过订阅拥有数据的服务发布的 Domain 事件来使数据库保持最新。这个数据库通常是 NoSQL 数据库,比如文档数据库或键值存储。
比如下面示例图,为了查询用户的订单历史记录,专门建立了一个订单历史记录服务,其订阅了订单服务、
需要考虑的点
- 数据一致性:CQRS查询分离的思想,提前组装好视图,解决了从多个服务拉取和组装数据的性能问题,但是同时由于分离了读写的数据源,因此会在数据同步和组装的过程中不可避免的会有暂时的数据不一致的问题。数据不一致问题是一个需要考虑业务实际情况处理的问题。
无端联想:首先是要考虑业务本身特性是否能容忍“暂时”的数据不一致的情况。其次,对于上面举例的订单场景,可以考虑离线和在线结合的方式,即对于已经完成的订单列表,采用离线的方式组装好相关数据,对于进行中的订单,其状态可能发生改变,采用在线查询的方式。考虑到进行中的订单数量一般不会太多(个位数),两种形式订单拼接在一起也不太会引入新的列表页异构数据源合并的问题MySQL和Redis一起之后如何分页|异构数据源列表页合并[^1]。
- 服务复杂性:毕竟引入了需要订阅事件和处理的步骤和视图相关的数据库,相比于直接查询的架构引入了更多的复杂度。
其它
CQRS是一种查询优化的思想,其也可以升华到到读写职责分离的系统架构。这种思想与DDD的思想有很多契合的地方。
参考:
CQRS的精要应用说明:Pattern: Command Query Responsibility Segregation (CQRS)
经典的应用系统结构、CQRS与事件溯源 - dax.net - 博客园
DDD CQRS架构和传统架构的优缺点比较 - netfocus - 博客园
感谢大家阅读到这里!🎉
如果你有任何问题或想法,欢迎在评论区留言,我们一起讨论、一起进步!
如果你觉得这篇文章对你有所帮助,也请不吝点赞、分享,支持博主继续创作更多优质内容!💪
关注【小菜先生的编程随想】公众号,我们一起在编程的道路上越走越远,战胜一切挑战!💥
希望可以下次再见!👋

浙公网安备 33010602011771号