前言
ENode是一个应用开发框架,为开发人员提供了一整套基于DDD+CQRS+ES+EDA架构风格的解决方案。ENode从发布1.0开始到如今的差很少两年时间,我几乎每周都在更新设计或实现代码。以致于历来没有一个稳定的版本能够提供给你们,很是惭愧。但我相信,随着时间的推移和个人努力的积累,ENode必定会愈来愈稳定和成熟的。我以为我此刻很幸福,由于我有本身的兴趣且有机会在业余时间为了本身的兴趣而奋斗。node
ENode开源地址:https://github.com/tangxuehua/enodegit
今天是个开心的日子,由于我终于使用ENode开发出了一个比较有说服力的真实案例,一个在线会议位置管理与订购系统。该案例与微软的Microfost CQRS Journey案例的功能一致,只是是用ENode开发完成的。目的是为了展现:github
- 如何使用ENode支持DDD领域层的实现;
- 如何使用ENode实现CQRS+ES的架构;
- 如何使用ENode实现事件驱动的架构(EDA);
另外,在案例开发过程当中,也不断发现了ENode, EQueue的不少问题。因此,经过作这个案例,也帮助ENode, EQueue完善了不少。真是要实践才能进步啊!服务器
ENode架构简介
ENode目前的架构已经和最初的1.0版本有较大的差异了。好比,没有了对Redis的依赖,增长了Command Store的设计。最新版本的ENode架构图以下:架构

熟悉CQRS架构的人应该对这个图不太陌生。须要强调的有两点:并发
- 新版的架构图中,Domain Aggregate是常驻内存的;聚合根的职责就是封装状态、业务规则,同时产生领域事件;
- 新增了一个Command Store,用于实现Command的幂等处理;
关于图中的其余部分的介绍,请参看我以前写的关于ENode系列的文章。 app
ENode关键特性
- 实现了CQRS架构,支持分布式,基于队列的水平扩展,框架设计之初就考虑了架构的各个节点的水平扩展;
-
面向高并发设计;架构层面,充分考虑到了如何解决并发问题;经过用EQueue实现服务器之间的消息路由、经过单机内部实现相似Actor Mailbox的设计,从而避免并发的产生。提升CQRS架构C端的总体写入吞吐量;即使在某些极端状况下出现并发问题,也支持自动的乐观检测,并自动重试;另外,架构层面,规定一个command只能涉及一个聚合根的修改,从而规范应用开发者必须严格按照消息驱动的思路来实现复杂的业务流程,而不能使用工做单元的方式,以事务的方式实现数据的强一致性;框架
- 严谨的消息幂等处理支持;因为ENode是消息驱动的架构,因此对消息的幂等性处理,是框架关注的一个重要的方面,并在架构层面作了支持。这使得应用开发人员没必要担忧消息的重复处理带来的问题。
- Domain Aggregate常驻内存;这个设计能够提升C端command的处理性能。由于咱们没必要像传统的方式那样先把聚合根从db取出来,再修改,再保存回去了;
- 框架为开发人员展现了如何更好的实现Sagas,在CQRS架构中,Sagas指基于消息驱动的业务流程;一个Saga包含若干个聚合根以及一个(一般)流程管理器(Process Manager);聚合根维护流程中的全部参与者对象的状态以及流程自己的状态,流程管理器负责定义和实现流程控制逻辑,无状态;流程管理器的实现是经过响应事件、异常、应用层消息,而后发送相应的命令,从而实现消息驱动的流程;
- 采用Event Sourcing(简称ES)的方式来持久化聚合根状态;经过ES实现聚合根状态的还原以及通用的并发控制,经过聚合根ID+事件版本号做为惟一索引的思路实现乐观并发控制;
- 消息除了command, domain event外,还支持exception message, application message;这两种消息是咱们在遇到有些消息不适合用domain event来表达时须要使用到;好比聚合里有时咱们要修改某个状态前会先作业务规则的检查判断,若是不合法,一般会抛异常,而后这个异常咱们又但愿可让流程管理器知道,从而流程管理器能够作后面的回滚或补偿措施;另外,咱们有时可能会在应用层面(command handler里)和其余外部系统发生交互,那交互的结果,使用应用层的消息更合理;ENode在架构层面,对上面这些消息作了统一的支持;
- 框架提供返回单个command执行结果以及阻塞等待command执行结果的支持,这个对于开发者但愿同步执行command并知道command执行结果的时候,很是有帮助;这样开发者就不用本身去轮训了。
- 除了对消息的幂等处理的支持外,ENode对domain event的顺序处理,也作了充分的考虑和支持,确保当C端产生的domain event同步到Q端时,Q端处理时,框架层面能确保Q端的处理顺序不会乱序。从而保证C,Q两端的数据是最终一致的;
- 保证消息能至少被处理一次;主要思路是确保消息的:1)持久化;2)消息ACK后才认为已消费;
- 支持一个聚合根一次能够产生多个domain event;虽然大部分状况,一个聚合根一次只会产生一个domain event,但有些场景,可能会产生两个或多个。此时,这些事件会以一个事件流的方式一块儿apply到当前聚合根;同时,在Q端,框架也会经过必要的手段,与用户代码一块儿保证了事件流中的事件的处理顺序的正确性;
- ENode所使用的分布式消息队列EQueue,参考了阿里的RocketMQ的架构思想,具备高性能、可扩展、轻量级的特性,支持不受限于机器内存大小的消息堆积能力,并且是纯C#开发。同时还提供了简单实用的管理控制台,可让咱们轻松的管理消息队列。好比能够方便的动态增长、禁用、启用、删除队列,查询消息内容、消息消费进度,等信息;目前,EQueue也已经通过多个迭代,而且已经有真实用户进行使用,功能基本趋于成熟稳定。
Conference案例简介
Conference是一个微软开发的,基于DDD+CQRS+ES的一个开源项目。项目主页:cqrsjourney.github.iodom
这个项目,对咱们你们学习DDD领域驱动设计、CQRS+ES的架构,很是有帮助。分布式
- 该案例从业务上,实现了一个典型的电子商务系统的关键环节:商品管理、库存管理、下单、减库存、支付;
- 该案例从技术上,很好的展现了CQRS架构的优势。好比能够在Q端定制不一样的视图,以应对不一样的查询需求;
- 该案例很好的向咱们展现了如何划分领域,划分边界上下文(bounded context),并如何使用不一样的架构技术,实现不一样的上下文,很是具备学习价值。
正是由于这个项目的以上优势,让我有兴趣使用ENode做为技术支撑,实现一样功能的系统。在重写的过程当中,保留了全部非技术的东西,好比边界上下文的划分、领域层等;全部技术相关的部分,用ENode替代。
使用ENode实现的Conference开源项目地址:https://github.com/tangxuehua/conference
演示地址,后台:http://www.enode.me/conference,前台:http://www.enode.me/registration
但愿有兴趣的同窗,能够去下载源代码进行研究。了解ENode,最快的方法就是从案例代码开始。若是想进行交流,能够加QQ群:185916873,随时欢迎有兴趣的道友加入。
最后,贴一个Conference案例中订单处理的Sagas流程图:

不早了,实在写不下去了,就到这吧。