CQRS——命令与查询职责分离【翻译】

标签: cqrs 命令 分离 | 发表时间:2013-12-30 22:51 | 作者:liuzhaodong89
出处:http://www.iteye.com

CQRS

翻译自大牛Martin Fowler的CQRS。原文地址:http://martinfowler.com/bliki/CQRS.html

==================================================================

CQRS代表着命令查询责任分离。我第一次听到这个模式是从Greg Young那里。这个模式的核心就是你在更新数据时所使用的模型可以与读取和查询时所用的数据模型不一样。这个最为简单的概念实际上却引出了在信息系统设计上具有深远意义的一些结论。

实际上用户与信息系统进行交互的主旋律方式,还是将信息系统当做一个能做增删改查的数据库。我的意思是指当我们新增记录、修改记录、读取记录和删除记录的时候,我们对它实际上已经建立了心智模型。在最简单的场景里,我们对数据的操作实际上就是写入和读出两种。

然而随着我们的需求变得越来越复杂,系统实现也一点一点的脱离最初的模型。也许我们希望能够有其他的方式来查阅数据库中的数据,比如将多条数据扁平化为一条,或者将来源于不同系统的数据组成虚拟的记录来展现。在存储端我们也许会发现校验规则或许只允许固定的几种数据组合被持久化,甚至要求用不同于上层提供的数据模型的方式来持久化数据。

当这些情况发生的时候我们开始思考信息的多种表现方式。当用户对用户进行互动操作的时候,他们会使用各种不同的数据展现样式,其中每一种实际上都是一种具有代表性的模式。开发人员通常会在开发时建立他们自己的模型来操纵系统模型中所用的核心部分。如果你在使用一个领域模型,那么它通常是对一个领域在概念上具有代表性的模型。你也可以将持久化的数据模型设计的尽可能与概念模型一致。

这种多层次的代表性模式架构可能会很复杂,但在实际应用中程序员通常会将其简化为一个的概念上的代表模型,而这个代表模型聚合了所有的展现方式。

CQRS带来的变化就是将原本统一的概念模型拆分成更新和查询时所使用的不同模型,就是CommandQuerySeparation这个单词中的命令(Command)和查询(Query)。这么做的原理是对于很多问题,尤其是那种十分复杂的领域,执行命令和进行查询时使用相同的模型会导致更加复杂的情况,而且此时的模型可能对哪种情况都无法完全满足。

通过拆分模型我们通常会隐含的暗示着这是不同的模型对象,可能运行在不同的逻辑流程中,甚至可能是在不同的硬件资源上。一个web上的例子是,用户看到的页面是通过查询模型渲染出来的。如果用户提交了一个变更,这个变更路由到了正确的命令模型上并且执行了,那么作为结果查询模型会通过通信的方式获知这个变更并更新渲染出的数据。

当然我们也为可能的变化做了提前准备。内存中的多种模型可能会基于同一个数据库,此时数据库作为不同模型间的数据沟通方式。与此同时不同的模型间也可以依赖不同的数据库,比如通过采用报告型数据库来高效的搭建起查询端的数据库。在这种情况下就需要其他的数据沟通方式来完成模型或数据库间的数据同步问题。

查询和命令两种场景下的模型不一定是两个完全不同的模型,他们也许只是有着不同的接口用以满足所在的场景。这更类似于数据库中的视图概念。但是当提到CQRS的时候,有一个清晰的信号就是这些模型是完全不同的。

CQRS天然的能够与其他一些架构模式相配合。

当我们抛弃原有的基于增删改查方式的代表模式时,可以轻易的迁移到基于任务的UI界面上。

以命令模式作为蓝本设计会自然而然的使用到命令和事件,而这些又引出了事件溯源。

同时拥有多个独立的模型增加了保持数据一致性的难度,同时也增加了使用最终一致性策略的可能性。

在许多领域里,更新数据时可能会涉及到大量的规则校验,所以采用饥饿式更新的策略可以简化查询端的复杂度。

增删改查的方式适用于比较复杂的领域,但同时领域驱动模式也适用。

什么时候使用?

和其他的模式一样,CQRS也有适用的场景。许多的系统本身更加适合用传统的增删改查模式,那么就应该用那个模式。CQRS对于所有人来说在思维上都是一个大的跳跃,所以除非你真的清楚CQRS能带给你的好处否则不要轻易尝试。

尤其CQRS应该只在一个系统的特定部分中(DDD中所说的有边界的上下文)使用而非整个系统。以此推而广之,一个系统中的每个具有边界的上下文领域都应该根据其自身特点决定建模方式。

到目前为止,我看到的CQRS带来的益处有两个方面。首先是对复杂性的掌控——一个复杂的领域可能更加适合CQRS。我必须要澄清的是,实际上仍然有很多情况下查询和命令共享数据模型会更简单,这个必须具体问题具体分析。

另一个好处是对高性能的支撑能力。CQRS能够让你将读和写分开,使得单独对读或写进行扩展变的很容易。如果你的系统在读和写两方面有非常大的不同,那么CQRS会很适合。即便不能如此,你也可以针对两个方面各自选择最优的优化方案。一个例子就是对读和写采用不同的数据库读取方案。

如果你的系统不适合使用CQRS,但同时也面临复杂度或者性能的问题,别忘了你可以使用从属数据库(ReportingDatabase)。CQRS中所有的查询都使用不同的数据模型。通过从属数据库你可以继续用主库支撑绝大部分的请求,将对应的更吃力的请求转移到从属数据库上。

目前为止我们还没有足够的CQRS实践经验,无法对其好处和缺点完全了解。所以尽管CQRS是一个我很喜欢的模式,但我不会将它放到第一优先级上。



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [cqrs 命令 分离] 推荐:

CQRS——命令与查询职责分离【翻译】

- - 企业架构 - ITeye博客
翻译自大牛Martin Fowler的CQRS. 原文地址:http://martinfowler.com/bliki/CQRS.html. CQRS代表着命令查询责任分离. 我第一次听到这个模式是从Greg Young那里. 这个模式的核心就是你在更新数据时所使用的模型可以与读取和查询时所用的数据模型不一样.

Linux wget命令

- - CSDN博客推荐文章
wget是linux最常用的下载命令, 一般的使用方法是: wget + 空格 + 要下载文件的url路径. 例如: # wget  http://www.linuxsense.org/xxxx/xxx.tar.gz. 简单说一下-c参数, 这个也非常常见, 可以断点续传, 如果不小心终止了, 可以继续使用命令接着下载.

lsof命令

- - Dutor
  lsof, LiSt Opened Files, 列出打开的文件, 听起来很简单的样子. 但想*nix中很多其他工具一样, lsof把这件简单的事情做到了炉火纯青. 因为Unix认为”一切皆文件”, 那么”打开的文件”就不仅仅是传统意义上打开的文件了, 还可以是网络/Unix域套接字, 匿名/具名管道, 共享库文件, 目录文件, 设备文件等等.

sqlite3命令

- - 移动开发 - ITeye博客
转载自: http://www.cnblogs.com/frankliiu-java/archive/2010/05/18/1738144.html. SQLite库包含一个名字叫做sqlite3的命令行,它可以让用户手工输入并执行面向SQLite数据库的SQL命令. 本文档提供一个样使用sqlite3的简要说明.

Linux iostat命令

- - CSDN博客系统运维推荐文章
iostat用于输出CPU和磁盘I/O相关的统计信息. . iostat [ -c | -d ] [ -k | -m ] [ -t ] [ -V ] [ -x ] [ device [. iostat各个参数说明:. -c 仅显示CPU统计信息.与-d选项互斥. -d 仅显示磁盘统计信息.与-c选项互斥.

tcpdump命令

- - CSDN博客推荐文章
英文原意是dump traffic on a network ,即截获网络上的数据报,可以根据指定的网络接口来截获不同的数据报. 它会输出在某个网络接口上符合匹配表达式的报内容的描述. 当tcpdump完成抓包后,会打印出类似下面的内容: . 当然,在读取网络上的数据包时,得需要特权,比如linux上的超级用户.

linux命令locate

- - 操作系统 - ITeye博客
    locate命令其实是"find -name"的另一种写法,但是要比后者快得多,原因在于它不搜索具体目录,而是搜索一个数据库(/var/lib/locatedb),这个数据库中含有本地所有文件信息. Linux系统自动创建这个数据库,并且每天自动更新一次,所以使用locate命令查不到最新变动过的文件.

@lsof命令小节@

- - CSDN博客推荐文章
卸载移动存储时经常提示device busy,也可能误删了一个正在打开的文件.      lsof(list open files)是一个列出当前系统打开文件的工具. 在linux环境下,任何事物都以 文件的形式存在,通过文件不仅仅可以访问 常规数据,还可以访问 网络连接和硬件. 所以如传输控制协议 (TCP) 和用户数据报协议 (UDP) 套接字等,系统在后台都为该应用程序分配了一个文件描述符,无论这个文件的本质如何,该文件描述符为应用程序与基础操作系统之间的交互提供了通用接口.

linux常用命令

- - 梦幻主页的博客
1.# 表示权限用户(如:root),$ 表示普通用户.   开机提示:Login:输入用户名.   password:输入口令   用户是系统注册用户成功登陆后,可以进入相应的用户环境.   退出当前shell,输入:exit. 2.useradd netseek 添加一个netseek用户.   passwd netseek  给netseek这个用户设置密码.

strace命令小结

- - jackyrong
strace命令是很有用的进程跟踪命令,下面小结下:. 1 strace 是一个非常简单的工具,用来跟踪可执行程序的系统调用(system call). 最简单的使用是,它追踪可行程序运行时的整个生命周期,输出每一个系统调用的名字,参数和返回值. 但是它还可以做更多的事情:. 它可以基于系统调用或者系统调用组来过滤.