Skip to content

四火的唠叨

一个纯正程序员的啰嗦

Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接
Menu

API 设计:CQRS(命令查询职责分离)

Posted on 10/23/201110/07/2024 by 四火

以下内容翻译自 CQRS by Martin Fowler,有一些修改:

 

CQRS(Command Query Responsibility Segregation)指的是命令查询职责分离。这是一种我从 Greg Young 处听到的模式描述。它的核心思想很简单,就是你在更新和读取操作时使用不同的模型,这样的话,会给整个系统的设计带来深远的变革。

 

人们和信息系统交互的主流行为就是对数据仓库 CRUD 的使用,我们构思一个可以供创建、读取、更新和删除的数据模型。简单来说,我们的接口提供出来的目的就是供存储和获取数据之用的。

 

现在我们要脱离这样一种模型,看看另一种存储数据的方式,可能是把很多数据打包成一个数据对象,或者把一些数据按照某种格式压缩成一种新的格式存储起来。在数据更新这块,我们可以找到一些校验方式来对上述要存储的数据进行校验,甚至可以推断出我们提供的数据和现有的存储数据有什么不同。

 

传统方式:

image

 

这样一来,我们可以开始用多种视角来看待数据的呈现了。当用户和数据交互的时候,他们使用的是不同种的数据呈现方式。开发者通常会构建他们自己觉得正确的核心属性的概念模型,如果你在使用领域模型,那么这就是一种概念上的领域模型的表达,你当然也可以对数据的存储定义这样的一个概念模型。

 

今天提到的方式:

image

 

CQRS 则做了改变,它将这个模型拆分成命令和展示两部分,分别叫做 Command 和 Query。这样对于很多问题,特别是复杂的领域,相对于对命令和查询使用同一概念模型,复杂性降低。

 

把模型拆开来,这意味着可以用不同的逻辑进程、不同的硬件来做这两部分事情了。一个 WEB 上的例子,用户查看页面的时候使用查询模型;而如果要改变数据,这种改变会解析成若干命令模型来执行操作,操作完毕后通知状态的更新。

 

这里有一些变数需要考虑,内存中的两种模型可以来自同一个数据库,但也可以来自不同的数据库。比如可以让数据的查询来自实时的 ReportingDatabase(一种只提供读取服务的数据库概念,Bliki 上尽是概念,有的东西还真不怎么样,呵呵,译注),这样的话就需要一种存在于不同数据库之间的数据通信机制。

 

两种模型,那么原本相同的对象就需要不同的方法来操纵和查询了,就像关系数据库中的不同视图。不过我一听说了 CQRS 的介绍,这两种模型在脑海里一下子清晰起来。

 

我们把一个通过 CRUD 来交互的模型,挪到基于事件的 UI 层,对于基于事件溯源的场景我们使用命令模型。如何保持两种模型的一致性呢?这里需要考虑事件层面的一致性。很多情况下只有你在更新数据前才需要执行业务逻辑,所以使用 EagerReadDerivation(这个我不知道怎么翻译,建议大家打开链接看一看,读请求可以直接从 ReportingDatabase 中获取数据,而不经过逻辑处理,这个思路是有些奇特,见下面的图,译注)来简化你的查询模型是有很大意义的。

 

image

 

像很多模式一样,CQRS 只在某些场合适用,它带来了一种思维上的跳跃,如果不能从中获益,就不要考虑它。尤其值得一提的是,CQRS 只在某些特殊系统的某部分中使用(如面向领域设计中提到的 Bounded Context)。

 

目前为止我只看到只有两个方面在此获益。一个是针对非常复杂的场景,可以用 CQRS 简化问题。通常我尽量不这么做,因为在命令和查询两部分重叠较多,有足够多的方法属性可以重用;另一个情况是对于高性能的应用,如果读写比例太悬殊,

CQRS 可以让你分开考虑横向扩展,即便是传统方式,你也得对读写考虑不同的优化策略。一个例子是使用不同的数据库访问技术来处理查询和更新。

 

如果你的场景不适合使用 CQRS,但是你又面对查询的复杂性和性能问题,你仍然可以试试这个 ReportingDatabase,因为这样你仍然可以使用你原来的系统,只是对于一些特殊要求的查询,切换到这个 ReportingDatabase 上去(我通读了一下关于这个东西的文章,也没有见到它有特别优秀的地方,再者,对于这样一些变态场景,更可能会考虑的是一些成熟的读写库分离技术,译注)。

 

我们目前还没有看到很多使用 CQRS 的地方,我们理解大家对它赞成和反对的理由,CQRS 依然是我工具箱中必不可少的一把利器,虽然我不经常使用它。

 

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

×Scan to share with WeChat

你可能也喜欢看:

  1. 关于接口设计,还有 Fluent Interface,这种有趣的接口设计风格
  2. DAO 的演进
  3. LeetCode 数据库十道题解答
  4. YQL
  5. 程序的库设计

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

订阅·联系

四火,啰嗦的程序员一枚,现居西雅图

Amazon Google Groovy Hadoop Haskell Java JavaScript LeetCode Oracle Spark 互联网 亚马逊 前端 华为 历史 同步 团队 图解笔记 基础设施 工作 工作流 工具 工程师 应用系统 异步 微博 思考 技术 数据库 曼联 测试 生活 眼界 程序员 管理 系统设计 缓存 编程范型 美股 英语 西雅图 设计 问题 面向对象 面试

分类

  • Algorithm and Data Structure (30)
  • Concurrency and Asynchronization (6)
  • System Architecture and Design (43)
  • Distributed System (18)
  • Tools Frameworks and Libs (13)
  • Storage and Data Access (8)
  • Front-end Development (33)
  • Programming Languages and Paradigms (55)
  • Testing and Quality Assurance (4)
  • Network and Communication (6)
  • Authentication and Authorization (6)
  • Automation and Operation Excellence (13)
  • Machine Learning and Artificial Intelligence (6)
  • Product Design (7)
  • Hiring and Interviews (14)
  • Project and Team Management (14)
  • Engineering Culture (17)
  • Critical Thinking (25)
  • Career Growth (57)
  • Life Experience and Thoughts (45)

推荐文章

  • 聊一聊分布式系统中的时间
  • 谈谈分布式锁
  • 常见分布式系统设计图解(汇总)
  • 系统设计中的快速估算技巧
  • 从链表存在环的问题说起
  • 技术面试中,什么样的问题才是好问题?
  • 从物理时钟到逻辑时钟
  • 近期面试观摩的一些思考
  • RSA 背后的算法
  • 谈谈 Ops(汇总 + 最终篇):工具和实践
  • 不要让业务牵着鼻子走
  • 倔强的程序员
  • 谈谈微信的信息流
  • 评审的艺术——谈谈现实中的代码评审
  • Blog 安全问题小记
  • 求第 K 个数的问题
  • 一些前端框架的比较(下)——Ember.js 和 React
  • 一些前端框架的比较(上)——GWT、AngularJS 和 Backbone.js
  • 工作流系统的设计
  • Spark 的性能调优
  • “残酷” 的事实
  • 七年工作,几个故事
  • 从 Java 和 JavaScript 来学习 Haskell 和 Groovy(汇总)
  • 一道随机数题目的求解
  • 层次
  • Dynamo 的实现技术和去中心化
  • 也谈谈全栈工程师
  • 多重继承的演变
  • 编程范型:工具的选择
  • GWT 初体验
  • java.util.concurrent 并发包诸类概览
  • 从 DCL 的对象安全发布谈起
  • 不同团队的困惑
  • 不适合 Hadoop 解决的问题
  • 留心那些潜在的系统设计问题
  • 再谈大楼扔鸡蛋的问题
  • 几种华丽无比的开发方式
  • 我眼中的工程师文化
  • 观点的碰撞
  • 谈谈盗版软件问题
  • 对几个软件开发传统观点的质疑和反驳
  • MVC 框架的映射和解耦
  • 编程的未来
  • DAO 的演进
  • 致那些自嘲码农的苦逼程序员
  • Java 多线程发展简史
  • 珍爱生命,远离微博
  • 网站性能优化的三重境界
  • OSCache 框架源码解析
  • “ 你不适合做程序员”
  • 画圆画方的故事

近期评论

  • Ticket: TRANSACTION 1.922915 BTC. Go to withdrawal >> https://yandex.com/poll/enter/BXidu5Ewa8hnAFoFznqSi9?hs=20bd550f65c6e03103876b28cabc4da6& on 倔强的程序员
  • panshenlian.com on 初涉 ML Workflow 系统:Kubeflow Pipelines、Flyte 和 Metaflow
  • panzhixiang on 关于近期求职的近况和思考
  • Anonymous on 闲聊投资:亲自体验和护城河
  • 四火 on 关于近期求职的近况和思考
  • YC on 关于近期求职的近况和思考
  • mafulong on 常见分布式基础设施系统设计图解(四):分布式工作流系统
  • 四火 on 常见分布式基础设施系统设计图解(八):分布式键值存储系统
  • Anonymous on 我裸辞了
  • https://umlcn.com on 资源链接
© 2025 四火的唠叨 | Powered by Minimalist Blog WordPress Theme