Event Sourcing - ENode(一)

分布式系统



摩尔定律如果一直能实现,不管是涉及或者实现一个OLTP的系统,我们是不是都会轻松点,用硬件堆就可以了。但是现在硬件已经在求变了,那么我们也得求变,云的概念如此之火,本质就是设施虚拟化,也可以认为是逻辑化,那么我们做软件是不是也要来虚拟化一下呢,当然,软件本身就是虚拟逻辑化。

如果摩尔定律继续支持IO设备性能往上走,那就皆大欢喜,可惜不是这样。于是我们将系统做成多个实例,也许一个系统中还有很多子系统,全部实例化,一股脑扔进一个大的“计算机”里面,这个“计算机”是逻辑的,物理上就有太多组合了,可能在中国有一个服务器是一个系统实例或者子系统实例,在美国也有。从外面看,就是一个完整的系统,从内部看,由多个系统实例组成,因为是逻辑隔离的,所以认为是分布的。

一个系统的多实例,也许是部署在不同机器上,或者容器,或者单台机器,但是他们都是独立的运行单元了,假如将他们理解为在一个机器上运行的多个程序,要协调他们正常运作,那么我们是不是需要模拟操作系统呢,这就是分布式系统的基础设施,基本上与操作系统的各个基础设施所对应,甚至实现方式都类似,不过在现实当中连接他们的是网线而不是总线。

关系数据库



ACID特性,实质上ACID只是一种指导思维,其实现有各种各样,不管是ORACLE、MSSQLSERVER、MYSQL以及其他关系数据库,大多实现了ACID,我们的系统有各种需求,有时特别需要数据一致性,例如账号存钱取钱之类的场景,所以在关系数据库上我们是基本放心的。在把系统设计成分布式之后,无论我们怎么拆系统,都会因为系统与关系数据库这个短板耦合而无法适应,于是后来的CAP,BASE理论就相继出现了。关系数据库是一个成熟的集成好的软件,我们无法控制,所以干脆我们抛弃ACID中不适应我们系统的需要特性,于是我们将关系数据库给拆了,将存储拆成一个基础设施,其他的我们按需来设计,比如需要一致性的我们用最终一致性来代替,实质上我们将关系数据库的各种组件都拆出来自己来实现。当然这里严格来说不能认为是实现了关系数据库,只能说借鉴了它的一些特性衍生到现在这样。因为没办法,于是我们只好将各种组件拆成可以分区扩展的组件。拆完了数据库,换种说法是持久化设施,我们就可以拆我们的系统了,不拆也可以,直接使用分区扩展的实例,没有问题,因为我们已经将短板给干掉了。

领域驱动



物理架构差不多了,我们需要考虑考虑真正的业务架构与逻辑架构了,DDD的理论不细说,业务架构从DDD的映射来看,可以认为是上下文,当然在物理视图当中,它也许是多实例的。那么对于每个上下文的逻辑架构呢,目前来说,应用最广泛的是经典的4层架构,也有很多变种,根据实际项目的需要,我更喜欢采用六边形架构,不过在实际项目中,我们的采用的框架所面对的问题更实际,可维护性,可扩展性可能更需要注重,也许一个聚合根的概念就需要沟通很多次,各种概念是因人而异的,不管怎么实现,只要最后有这个功能满足了功能需求与非功能需求即可。所以也许最后又变回了原始的3层架构。如果我们坚持贯彻了DDD的概念,那么未来在可扩展上一定是非常方便的。所以要实现DDD,团队成员的要求是比较高的。

CQRS ES



CQRS典型的借鉴了我们在优化关系数据库架构中常用的方法,读写分离。在写DDD的时候,是不是碰到过模型适应写与读场景的不匹配,各种令人烦躁的ORM的N+1问题,也许已经想办法从框架内实现了只读模型的DTO,用CQRS来形容并形成一个标准更能让大家接受。不同的架构师面对同一个问题有不同的解决方案,但也许只是变种,如果能统一大家的使用方式形成专业的语言,例如领域语言,那么我们就可以集合大家的力量齐头并进了。CQRS就算是一种。

为什么要使用ES呢,我们来想想关系数据库实现数据一致性的方式,假如我们要插入一条数据,数据库先写日志,然后插入表中,这样的描述不够准确,但大致如此,不要纠结,我想说的是关系数据库采用了一种方式称为写屏障,在真实写入之前先记录,在异常情况下,我们就可以保持数据的一致性,现在Linux的很多新型文件系统就是采用了此种方式,那么ES呢,也是一种写屏障,只不过将数据定义为了面向DDD中的领域事件,我们可以通过Event来查询源头重新演绎领域对象的状态。同时,我们也在ES中使用了写屏障,那么这里我们也实现了一致性,不过是最终一致性。但是如果我们从关系数据库来看,其本质也是最终一致性,例如关系数据库在插入数据的某一刻它突然断电,重启之后,查询日志,该插入的数据还是插入(逻辑不是如此简单),那么从内部来看都是最终一致性。

从性能角度来考虑,那就有关于聚合根的粒度了,聚合根的粒度越细,Event必然越多。

ENode



EDA ES框架

前面所讲的都是我在看到ENode框架之后想到的,ENode框架不仅满足了分布式的需求,在DDD以及ES的概念上真正的做成了可以使用的框架,只要对DDD以及CQRS的概念理解的足够深,那么使用它将会是最好的选择。

要想使用ENode的所有特性完成项目,那需要团队成员对DDD有足够多的理解。

因为想采用ENode框架,所以将预研ENode框架的过程和大家分享一下。

在业务的可扩展性我们从DDD上我们就可以保证,所以无需多说。

引用作者的设计图

因为是预研性的项目,所以对于框架的易用性、易理解性、维护性,关注的稍微要少些。更多的是想理解作者的设计思想。

关注框架是否能满足项目的非功能需求、核心功能需求,所以先尝试关注以下几点:

1. 分布式

划分好上下文后,采用ENode框架实现,就可以直接使用分布式的基础设施将上下文的多个实例连接起来。

其实ENode本身就是支持分布式的,内部采用了作者自己编写的消息中间件EQueue,EQueue有点类似于Apache Kafka的设计,也是支持动态扩容的消息框架,从性能上来说整个就满足了分布式的需求。

2. 是否能满足一致性

(1)从写屏障的角度来说,ES可以部分支持一致性,一致性在分布式的环境中实现的方式有多种,涉及到几个概念,对一个操作至少执行一次,绝对只执行一次,当然还可以自己设计,例如不知道执行与否,就是我会执行但不知道执行结果。扯远了,如果要绝对只执行一次,在实现以及性能上都会有一些折扣,作者采用的是至少执行一次,怎么讲呢,至少执行一次所遵从的原则是必须经过了写屏障,如果没经过写屏障,那么我们可以认为这是无效的,经过了写屏障,系统宕机,可以通过ES重新发起事件。这里执行的就是Domain Event。

既然是至少执行一次,那就会有幂等的处理,作者设计非常灵活,允许使用者自己来装配,在作者的Sample中,使用了MSSQLSERVER来持久化Event,通过MSSQLSERVER中的唯一约束做乐观锁来做到幂等。

在聚合根的内部采用乐观锁来消除幂等,可以在很多个地方使用乐观锁,不管是ENode框架本身提供的,例如在Command Store、Event Store处由SQLSERVER来实现,也可以通过ZooKeeper实现,作者也提供了分布式悲观锁的接口以及采用SQLSERVER的实现,乐观锁就像是一个检查点,台湾人喜欢称这种检查点为机关,我们可以设置合适位置设置合适数量的机关来检查并发。

(2)对应关系数据库的隔离性,在作者的设计中,是按照聚合根来隔离并发的。

使用了聚合根的粒度来实现隔离,在聚合根内部采用了乐观锁或者悲观锁,减小了锁的粒度,来换取性能的提升。

在作者的设计图中还未完全标注出一些组件,

CommandHandler,EventHandler,ApplicationMessageHandler,ExceptionMessageHandler,不是很准确,有兴趣的朋友可以自行查看源代码。

Command、Event是DDD的领域语言

ApplicationMessage、Exception是作者在框架设计的框架领域语言

这些都是作为底层的可传递的消息,可以理解为分布式的消息,上面罗列的Handler都是作者默认实现的,采用的是Actor模式,都是有自己的MailBox,那么其实现就是顺序的并且是单线程的。在某一时刻,单个的系统实例中,Command、Event、ApplicationMessage、Exception都是在并行,但他们内部是只有一个在运行实际的逻辑。这也是可以装配的。

时间: 2024-08-27 11:17:34

Event Sourcing - ENode(一)的相关文章

Event Sourcing - ENode(三)

接上一篇 http://www.cnblogs.com/dopeter/p/4903328.html 老板昨天在第二篇介绍中回复代码和文字无法一一对应.为了更好的让老板为大家解惑,把第二篇最后的猜测的问题搞清楚后,就补上其他文字说明的代码图. 在上篇中泛泛介绍了Commanding,比较跳跃,目前是想到哪写到哪,后续分门别类的整理. 在后续中会补全ENode框架的装配关系,其实作者的接口命名已经非常清楚了. 无论作者使用了什么样的装配的设计模式,目的都是为了更好的扩展与维护.一般能直接组合的就直

Event Sourcing - ENode(二)

接上篇文章继续 http://www.cnblogs.com/dopeter/p/4899721.html 分布式系统 前篇谈到了我们为何要使用分布式系统,因为ENode本身就是一个分布式的框架.看了很多DDD.CQRS的框架,一般情况是一个上下文一个系统,可以多分系统实例进行分布式部署,但需要自己搭配分布式的基础设施.而ENode已经提供了较为完整的分布式DDD解决方案. 1. 分布式通讯基础设施 一般使用RPC.MOM.REST,不过最近REST已经逐渐弱化特别是在一个大系统的内部,或者是对

Event Sourcing

Event Sourcing - ENode(二) 接上篇文章继续 http://www.cnblogs.com/dopeter/p/4899721.html 分布式系统 前篇谈到了我们为何要使用分布式系统,因为ENode本身就是一个分布式的框架.看了很多DDD.CQRS的框架,一般情况是一个上下文一个系统,可以多分系统实例进行分布式部署,但需要自己搭配分布式的基础设施.而ENode已经提供了较为完整的分布式DDD解决方案. 1. 分布式通讯基础设施 一般使用RPC.MOM.REST,不过最近R

CQRS, Task Based UIs, Event Sourcing agh!

原文地址:CQRS, Task Based UIs, Event Sourcing agh! Many people have been getting confused over what CQRS is. They look at CQRS as being an architecture; it is not. CQRS is a very simple pattern that enables many opportunities for architecture that may ot

[设计模式] Typed Message模式与Event Sourcing

引言 在<设计模式沉思录>(Pattern Hatching: Design Patterns Applied,[美]JohnVlissides著)一书的第4章中,围绕事件Message传递的推-拉模型(Push-Pull),谈到了一个最初被称为Multicast,之后被定型为Typed Message的设计模式. 该模式的初衷是希望得到一个可扩展的.类型安全的事件传递机制,并能符合两点要求: 通过推模型来将事件传递给消费者. 特有的每个事件只需要最多新增一个类,而不需要对已有代码进行修改.

DDD创始人Eric Vans:要实现DDD原始意图,必须CQRS+Event Sourcing架构

http://www.infoq.com/interviews/Technology-Influences-DDD# 要实现DDD(domain drive  design 领域驱动设计)原始意图,必须CQRS+Event Sourcing. CQRS+Event Sourcing其实不但是一种全新思想,将可能颠覆Java或C#现有的编程体系. 使用传统JavaEE或Spring + Hibernate这样的框架,是无法实现DDD原始意图的,这个DDD创始人Eric Vans已经说过:2012年

[外文理解] DDD创始人Eric Vans:要实现DDD原始意图,必须CQRS+Event Sourcing架构。

原文:http://www.infoq.com/interviews/Technology-Influences-DDD# 要实现DDD(domain drive  design 领域驱动设计)原始意图,必须CQRS+Event Sourcing. CQRS+Event Sourcing事实上不可是一种全新思想.将可能颠覆Java或C#现有的编程体系. 使用传统JavaEE或Spring + Hibernate这种框架,是无法实现DDD原始意图的,这个DDD创始人Eric Vans已经说过:20

DDD CQRS 和 Event Sourcing 的案例:足球比赛

在12月11日新的有关DDD CQRS和Event Sourcing演讲:改变心态- 以更加面向对象视角看待业务领域建模中,作者以足球比赛football Match为案例说明传统编程方法和CQRS的区别. CQRS作为DDD的最佳实践已经得到广泛承认和普及,下面摘取该文章的PPT部分图片简单讲解一下,如何使用CQRS和Event Sourcing实现DDD系统. 首先,领域专家对需求进行定义: 举办一个比赛,有两个队参加 比赛在某个时间开始,只能开始一次. 比赛结束后,统计积分 作为用户,希望

DDD CQRS和Event Sourcing的案例:足球比赛

在12月11日新的有关DDD CQRS和Event Sourcing演讲:改变心态- 以更加面向对象视角看待业务领域建模中,作者以足球比赛football Match为案例说明传统编程方法和CQRS的区别. CQRS作为DDD的最佳实践已经得到广泛承认和普及,下面摘取该文章的PPT部分图片简单讲解一下,如何使用CQRS和Event Sourcing实现DDD系统. 首先,领域专家对需求进行定义:1.举办一个比赛,有两个队参加 2.比赛在某个时间开始,只能开始一次. 3.比赛结束后,统计积分 作为