一种简单的CQRS架构设计及其实现
一、为什么要实践领域驱动?
近一年时间我一直在思考一个问题:“如何设计一个松耦合、高伸缩性、易于维护的架构?”。之所以有这样的想法是因为我接触的不少项目都是以数据库脚本来实现业务逻辑。在项目初期使用这样的方式野蛮开发似乎显得很高效,但是大家其实都清楚,正是这样的项目让大家拖入了加班的深渊。这种系统维护性差,无法扩展,无法编写有效的单元测试,质量基本没有保证。
一个符合我心理预期的架构,一定不是靠使用某个代码生成工具来完成的,这样的项目把码农培养成了彻头彻尾没有思想的个体。一个有追求的码农,请远离只会让你使用代码生成工具的“架构师”。
既然数据库驱动的开发方式存在一些致命的问题,我们很自然的想到了领域驱动开发(DDD)。在《我眼中的领域驱动开发》一文中,我提到了领域驱动设计不同于传统软件开发的一些思考方式。这些思想看起来很简单,但是真正实践起,思维的转变还是有一定的难度。
在我职业生涯里遇到的每一个同事,在讨论问题时都能够表现出自己擅长的一面,有的人思路比较清晰,有的人想法比较特别,跟这些人在一起讨论方案往往都会够给你灵感。领域驱动开发这种方式需要融入有生命力的想法,每一个人都可以参与到设计当中,软件开发才会变成一件有意思的事情。
二、使用EF来实践领域驱动
我曾尝试使用单纯的EF来实践领域驱动开发,老实说,我没法实践成功。我想忘掉数据库,但是很难。为什么这样说?我们知道领域驱动讲求以领域模型为基本单位思考问题,比如一次购物过程可能是一个领域模型,我抛开了数据库,建立的模型。这时来了一个需求,一个界面需要能够查询一个范围内的购物记录,可能还有一些复杂的条件,这时候我的领域模型并不能很好的支持这样的查询,因为我在这之前压根没有考虑表结构如何设计,我的领域模型不是为查询设计的,所以这样的一个查询很容易存在性能问题。所以忘掉数据库这一命题很难实现。
三、为什么会存在这样的问题?
发生了这样的问题我就在思考到底是哪里出了问题,是领域驱动开发这种软件开发方式存在问题吗?
造成这种局面的根本原因在于“我们给Domain强加了查询的职责,长久以来的软件开发模式太过于依赖于关系数据库”,关系数据库的首要任务是持久化数据,查询只是他的部分能力,长久以来我们即想让关系数据库存储海量数据,又想让查询变得更高效。显然,我们对关系型数据库的要求有点过分了。
我想这也是Greg Young提出了CQRS架构的原因,当我们在领域模型中去掉搜索和查询的职责后,问题引刃而解。
四、实现CQRS有哪些难点?
既然CQRS才是实践DDD的最佳途径,那么我们就可以使用CQRS了么?提到CQRS,不得不提到博客园的两位CQRS元老级人物,dax.net和netfocus,他们两位都贡献了自己的CQRS框架,但是我猜测,即便是他们两位大神也不会轻易在真实场景下使用CQRS架构。在我看来要真正实践CQRS需要天时、地利、人和三者具备。
1、经典的CQRS是通过Event Sourcing来实现领域模型的还原和Query端的同步,这就要求领域模型的设计一定要一次到位,一旦Event被持久化到生产环境,这时候再修改设计就会带来极大的难度。
2、对开发人员要求非常之高、要建立这样的一直团队需要长时间的磨合和培养。
3、采用CQRS的DDD由于对设计要求较高,所以在开发初期并不能很快看到效果,这就要求公司能够容忍、理解并且支持,这条似乎是最难符合条件的。
五、实现一个简单的CQRS方案
经过分析,要想成功实践领域驱动,查询与命令职责一定要分离,我们还是要实现CQRS,但是不再通过Event Sourcing来实现,从而减少复杂度。下面就是我的一个不太成熟的想法:
1、Domain通过EF持久化。
2、每个Domain逻辑在实现中都将产生两种固定类型的Event,***CreatedEvent和***UpdatedEvent。
3、由于取消了Event Sourcing,所以降低了Domain设计的复杂度,此时的关系型数据就相当于最新的快照。
4、在EF的UnitOfWork执行成功后注册发布事件的回调,确保领域模型持久化成功才发布事件。
5、事件发布到双工ServiceBus中,双工ServiceBus包含一个InMemory的同步ServiceBus和一个支持消息队列的异步ServiceBus。
6、领域发布事件后,先有InMemory的同步ServiceBus更新由Redis实现的QueryModel,确保界面会同步刷新,单个Domain的读取将通过Redis来实现。紧接着消息会发送到支持消息队列的异步ServiceBus。
7、消息进入消息队列后供其他子系统消费,同时更新Elastic Search,界面的复杂搜索将通过Elastic Search来实现。
8、此时的系统已经演化为一个松耦合、可扩展、基于领域模型的分布式架构方案。
当查询和读取Domain的职责被分摊到Elastic Search和Redis后,这时候再设计领域模型就不会有外界因素来干扰你。
另外整个系统不会出现一句sql,让sql这种反人类的语言去见鬼吧,此时要是还有谁要是觉得“必须得写sql,sql效率高”。你过来,我保证不打死你。o(^▽^)o
目前的Demo基于以上的想法正在一步步实现中,请关注。另外,由于水平有限,整个架构设计难免有不合理的地方,欢迎提出宝贵意见。
https://git.oschina.net/richieyangs/BookLibrary
一种简单的CQRS架构设计及其实现的更多相关文章
- CQRS架构设计及其实现
CQRS架构设计及其实现 一.为什么要实践领域驱动? 近一年时间我一直在思考一个问题:“如何设计一个松耦合.高伸缩性.易于维护的架构?”.之所以有这样的想法是因为我接触的不少项目都是以数据库脚本来实现 ...
- .net mvc中一种简单的工作流的设计
开篇前的废话:工作流是我们在做互联网应用开发时经常需要用到的一种技术,复杂的工作流我们基本是借助一些开源的 工作流项目来做,比如 ccflow等,但是有时候,我们只需要实现一些简单的工作流流程,这时候 ...
- SpringBank 开发日志 一种简单的拦截器设计实现
当交易由Action进入Service之前,需要根据不同的Service实际负责业务的不同,真正执行Service的业务逻辑之前,做一些检查工作.这样的拦截器应该是基于配置的,与Service关联起来 ...
- 架构设计:一种远程调用服务的设计构思(zookeeper的一种应用实践)
在深入学习zookeeper我想先给大家介绍一个和zookeeper相关的应用实例,我把这个实例命名为远程调用服务.通过对这种应用实例的描述,我们会对zookeeper应用场景会有深入的了解. 远程调 ...
- DDD CQRS架构和传统架构的优缺点比较
明天就是大年三十了,今天在家有空,想集中整理一下CQRS架构的特点以及相比传统架构的优缺点分析.先提前祝大家猴年新春快乐.万事如意.身体健康! 最近几年,在DDD的领域,我们经常会看到CQRS架构的概 ...
- ENode框架Conference案例分析系列之 - 架构设计
Conference架构概述 先贴一下Conference案例的在线地址,UI因为完全拿了微软的实现,所以都是英文的,以后我有空再改为中文的. Conference后台会议管理:http://www. ...
- 微软&中科大提出新型自动神经架构设计方法NAO
近期,来自微软和中国科学技术大学的刘铁岩等人发表论文,介绍了一种新型自动神经架构设计方法 NAO,该方法由三个部分组成:编码器.预测器和解码器.实验证明,该方法所发现的架构在 CIFAR-10 上的图 ...
- .net架构设计读书笔记--第三章 第10节 命令职责分离(CQRS)简介(Introducing CQRS)
一.分离查询命令 Separating commands from queries 早期的面向DDD设计方法的难点是如何设计一个类,这个类要包含域的方方面面.通常来说,任务软件系统方法调用可以 ...
- 一个简单可参考的API网关架构设计
网关一词较早出现在网络设备里面,比如两个相互独立的局域网段之间通过路由器或者桥接设备进行通信, 这中间的路由或者桥接设备我们称之为网关. 相应的 API 网关将各系统对外暴露的服务聚合起来,所有要调用 ...
随机推荐
- .Net多线程编程—并发集合
并发集合 1 为什么使用并发集合? 原因主要有以下几点: System.Collections和System.Collections.Generic名称空间中所提供的经典列表.集合和数组都不是线程安全 ...
- 如何一步一步用DDD设计一个电商网站(二)—— 项目架构
阅读目录 前言 六边形架构 终于开始建项目了 DDD中的3个臭皮匠 CQRS(Command Query Responsibility Segregation) 结语 一.前言 上一篇我们讲了DDD的 ...
- .NetCore中的日志(1)日志组件解析
.NetCore中的日志(1)日志组件解析 0x00 问题的产生 日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为.在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包 ...
- 【前端性能】高性能滚动 scroll 及页面渲染优化
最近在研究页面渲染及web动画的性能问题,以及拜读<CSS SECRET>(CSS揭秘)这本大作. 本文主要想谈谈页面优化之滚动优化. 主要内容包括了为何需要优化滚动事件,滚动与页面渲染的 ...
- 高性能IO模型浅析
高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking ...
- 谈谈一些有趣的CSS题目(九)-- 巧妙的实现 CSS 斜线
开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...
- OpenGL超级宝典笔记----框架搭建
自从工作后,总是或多或少的会接触到客户端3d图形渲染,正好自己对于3d图形的渲染也很感兴趣,所以最近打算从学习OpenGL的图形API出发,进而了解3d图形的渲染技术.到网上查了一些资料,OpenGL ...
- Android -- 真正的 高仿微信 打开网页的进度条效果
(本博客为原创,http://www.cnblogs.com/linguanh/) 目录: 一,为什么说是真正的高仿? 二,为什么要搞缓慢效果? 三,我的实现思路 四,代码,内含注释 五,使用方法与截 ...
- AFNetworking 3.0 源码解读(十)之 UIActivityIndicatorView/UIRefreshControl/UIImageView + AFNetworking
我们应该看到过很多类似这样的例子:某个控件拥有加载网络图片的能力.但这究竟是怎么做到的呢?看完这篇文章就明白了. 前言 这篇我们会介绍 AFNetworking 中的3个UIKit中的分类.UIAct ...
- Android实现TCP断点上传,后台C#服务实现接收
终端实现大文件上传一直都是比较难的技术,其中涉及到后端与前端的交互,稳定性和流量大小,而且实现原理每个人都有自己的想法,后端主流用的比较多的是Http来实现,因为大多实现过断点下载.但稳定性不能保证, ...