Event Sourcing - ENode(三)
接上一篇
http://www.cnblogs.com/dopeter/p/4903328.html
老板昨天在第二篇介绍中回复代码和文字无法一一对应。为了更好的让老板为大家解惑,把第二篇最后的猜测的问题搞清楚后,就补上其他文字说明的代码图。
在上篇中泛泛介绍了Commanding,比较跳跃,目前是想到哪写到哪,后续分门别类的整理。
在后续中会补全ENode框架的装配关系,其实作者的接口命名已经非常清楚了。
无论作者使用了什么样的装配的设计模式,目的都是为了更好的扩展与维护。一般能直接组合的就直接组合,能隔离的就直接隔离,如果遇到无法处理的情况有句经典的话,当我们遇到无法解决的问题的时候,就增加一个中间层来专门解决这个问题。其实和现实中是很匹配的,还是借鉴了现实的智慧啊。同事A,同事B、我,当A与B在一件事有争执的时候,那我就充当Broker的角色吧,如果这件事非常重要,很有可能出现矛盾,于是我可能会求助他人,例如同事C或者领导,让他们分别与A、B沟通,又也许我会集中精神,在A的面前与B的面前使用不同的方式来沟通,那么就是Proxy了。呵呵,想到了就写下来了。继续正题。
EDA
目前很火的架构模型,这里的Event不是DDD中的Domain Event,纯粹是指这种架构风格的Event,当然某些情况下我们可以这么认为,不过这里先不套用。
假如现在在一个分布式的系统中,有2个子系统实例,ServiceA与ServiceB。
假如ServiceA的某一个功能是创建Account,ServiceB的某一个功能是发送邮件。
现在有个系统级的功能是当一个Account被创建后,向这个Account发送邮件。
那么ServiceA创建好Account后,会通知ServiceB发送邮件。它们之间会进行通讯。
Event可以认为是一种它们之间传递消息的模型,例如ServiceA创建了一个Account并发布一个Event叫做OnAccountCreated,当然在我们实际的实现中,会被描述成各种不同的类,在ENode中这个Event消息被作者定义为Message,Message就是一个Event,在一个Event里面会包含这个Event的信息,例如OnAccountCreated事件里面包含了新增账户的邮箱。
还有另外一种模型,就是我们传统实现的模型,可以借鉴CQRS的Command/Query,例如ServiceA创建了一个Account,调用ServiceB的发送邮件的方法,调用发送邮件就是一个Command,ServiceA命令ServiceB发送邮件。
是不是觉得有点像Pub/Sub与Request/Reply,对应的实现是RPC和MOM。
可以这么理解,但也不完全是。
一般我们使用Request/Reply的RPC框架,两边定义契约,假如我们这里的契约是面向功能,例如ServiceB定义一个SendMail(Account account);当ServiceA完成创建Account后就可以调用这个接口发送邮件。
如果我们使用Request/Reply能不能实现Event呢,完全可以,ServiceA使用RPC框架发送一个OnAccountCreated的事件至ServiceB,在OnAccountCreated事件中包含了Account的信息,ServiceB开始发送邮件。Event的处理有很多优雅实现,最简单暴力的方式是直接规定一个通用接口,根据传递过来的事件处理逻辑。
问题就在这里,使用RPC我们需要知道对方的契约,即便是REST我们也要知道URL即资源地址。通过Event的Wrapper我们实际上是消除了RPC当中双方的契约,REST这边的资源地址。我们的契约面向的是什么角度,也就是解耦了什么角度,例如如果我们契约是业务型契约,就是解耦了业务也可以认为是功能,ServiceA不用知道ServiceB有发送邮件的功能。ServiceA只需要发送一个Event至ServiceB即可,也许不是OnAccountCreated事件。
这样通过Event我们实现了消息层面的解耦,本质上Event是一个消息的抽象。Event包裹了真实的业务消息,再次证明中间层这句话的适用性。不过这句话还有后面半截,这里不扯远了。
但是这时ServiceA是必须知道ServiceB的,MOM可以不让ServiceA不必知道ServiceB。
所以MOM+Event实现了分布式的EDA,对ServiceA来说,不用知道在创建完Account后下一步需要做什么,由谁来做。通过MOM来隔离主从关系。
从另外一个角度来看Request/Reply以及Pub/Sub。
Request/Reply发送Command,还是刚才的场景,ServiceB需要返回结果或者不返回结果,从组件运行层面来看,它是同步的。我们可以这样实现,使用Event,例如ServiceA发送OnAccountCreated事件至ServiceB,ServiceB发送OnMailSendCompleted事件至ServiceA,如果这个业务场景ServiceA必须得到邮件发送成功才能执行后续操作,那么仍然是同步的,另外种解释我们可以认为是同步非阻塞的。
Pub/Sub+Event,我们也就可以认为是异步非阻塞的。
那么EDA的真正威力就体现出来,可扩展性,吞吐量,都会上升。
EDA In ENode
说了很多EDA的话题,还是来ENode里面看看作者的实现。
前面介绍过,ENode分布式的粒度,在开发者应用层范围内定义了4种Event :Application Message、Command、Domain Event、Exception,可以将他们认为是EDA中Event在CQRS框架场景中的实例,其实这么说并不准确,应该是在ENode框架中作者定义好要用Event包裹的框架消息类型。EDA的组合还会有个MOM,则是作者自己实现并开源的EQueue。下图中所示的不是EQueue项目,实际上是EQueue在ENode项目中的Proxy。

一目了然,分别是4种消息的Pub/Sub。让我们看看其中一个的实现,就更清楚了。
先看最简单的ApplicationMessage

Consumer 消费者,Subscribe(string topic);订阅一个主题,这里就能够看到MOM的存在。
IQueueMessageHandler.Handle(QueueMessage queueMessage, IMessageContext context)方法,Consume还充当了一个Dispatcher的角色。

Publisher 发布者,PublishAsync方法,发布一个消息,这里为什么没有Topic呢,如下图主题。

作者已经拆分出去了,在每一个子系统里面可以定义开始所说4种消息类型的不同。我们可以自由的组合,例如将DDD中的应用层定义为一个Project,Domain定义为一个Project,横向或者纵向的扩展都是可行的,其实可以对应目前比较火的一种架构模型,微服务。
让我们继续看看Command

Consumer 消费者
CommandMessage EQueue传递的信息,如下图所示

注意ReplyAddress,这是后面介绍要用到的属性。
CommandExecutedMessage 已经被处理过的Command消息
CommandResultProcessor 命令结果处理者 在这里不仅包括Command被处理的结果,还可以处理当前这条Command触发的Domain Event处理的结果,如下图所示。

可以通过CommandReplyType判别是Command还是DomainEvent的回执。
执行一个Command并获得这条Command处理的结果,是在执行一个Command时指定的。如下图

这里实际上就是前面介绍EDA所描述的Request/Reply+Event的方式,可以是同步非阻塞也可以是异步非阻塞,如下图所示

一般都遵守CQRS的原则,Command无返回并且是异步,作者这里通过Fututre的方式来获取Command执行的回执,针对的是一定要得到结果之后再继续下面逻辑的场景。有时可能也想直接得到结果,例如上图所示。这也是作者考虑到很多场景但不生搬硬套CQRS。
作者实现回执的方式如下面2张图所示


Consumer接收到消息后,处理完毕后,如果发现CommandMessage中的ReplyAddress存在,则通过SendReplyService向这个地址发送回执消息。
剩下的Domain Event和Exception也是差不多的Pub/Sub的组成。就不一一介绍了。
作者关于博文的说明
作者的说明在回复中,方便感兴趣的朋友查看,就复制上来了。
By netfocus:
Application Message、Command、Domain Event、Exception这些是ENode中定义的4种消息,他们都实现了IMessage接口。IMessage是ENode中定义的一个通用的 消息接口。但和EQueue中的消息是两个层次的。EQueue中的消息的内容(payload)才是ENode中的IMessage。
架
构层面,一般流行的就两种架构:SOA,EDA。SOA属于RPC风格,一般是阻塞的,高并发时,吞吐量由于服务之间有依赖关系,所以整个系统的吞吐量受
限于最慢的服务的吞吐量;如果是EDA,属于PUB-SUB的风格,服务之间完全解耦,通过消息的topic来发生逻辑上的关系。系统的吞吐量不受任何一
个节点的限制;具体使用哪种场景要看情况而定,一般系统之间交互,还是用SOA风格的,系统内部的组件之间通信,我觉得EDA更好。
ENode.EQueue
是一个防腐层。用于把ENode和EQueue连接起来,但确保ENode,EQueue相互不知道对方的存在。ENode是一个EDA架构的风格框架,
所以需要一个分布式消息中间件,EQueue就是我开发的分布式消息中间件。如果我们要用其他的消息中间件,可以自己和其他消息中间件整合即可,比如写一
个ENode.RabbitMQ,ENode.Kafka,ENode.RocketMQ
ICommandService中提供的几个方
法,比传统的CQRS架构的定义确实要丰富一点,目的也是为了增加框架的实用性。具体使用哪个方法由开发者自己决定。通常一般我们在后台管理系统,希望等
读库也更新后才返回Command的,则可以调用ExecuteAsync并设置为等event也处理完后再返回的方式。如果是前台,用户不需要立即知道
处理结果的场景,则建议用SendAsync或Send即可。作为一个CQRS框架,我鼓励大家尽量考虑使用无返回值的方式,否则CQRS的效果就会打折
扣。
ENode作为一个框架,可以使用很多的OO特性,我觉得所有的OO设计原则或设计模式的核心就是隔离变化点,所以当我设计框架时,
首先要定义接口,明确接口的职责,然后接口实现类里发现有些东西是变化的,则进一步提炼其他接口出来,最后可以确保任何实现类内部使用的都是接口,这样整
个框架可以说任何地方都可以替代,增加了框架的可扩展性。
Event Sourcing - ENode(三)的更多相关文章
- Event Sourcing - ENode(二)
接上篇文章继续 http://www.cnblogs.com/dopeter/p/4899721.html 分布式系统 前篇谈到了我们为何要使用分布式系统,因为ENode本身就是一个分布式的框架.看了 ...
- Event Sourcing - ENode(一)
分布式系统 摩尔定律如果一直能实现,不管是涉及或者实现一个OLTP的系统,我们是不是都会轻松点,用硬件堆就可以了.但是现在硬件已经在求变了,那么我们也得求变,云的概念如此之火,本质就是设施虚拟化,也可 ...
- Event Sourcing
Event Sourcing - ENode(二) 接上篇文章继续 http://www.cnblogs.com/dopeter/p/4899721.html 分布式系统 前篇谈到了我们为何要使用分布 ...
- Typed Message模式与Event Sourcing
引言 在<设计模式沉思录>(Pattern Hatching: Design Patterns Applied,[美]JohnVlissides著)一书的第4章中,围绕事件Message传 ...
- CQRS与Event Sourcing之浅见
引言 DDD是近年软件设计的热门.CQRS与Event Sourcing作为实施DDD的一种选择,也逐步进入人们的视野.围绕这两个主题,软件开发的大咖[Martin Fowler].[Greg You ...
- Event Sourcing落地与意义
jsoncat:https://github.com/Snailclimb/jsoncat (仿 Spring Boot 但不同于 Spring Boot 的一个轻量级的 HTTP 框架) 高内聚低耦 ...
- Event Sourcing Pattern 事件源模式
Use an append-only store to record the full series of events that describe actions taken on data in ...
- CQRS, Task Based UIs, Event Sourcing agh!
原文地址:CQRS, Task Based UIs, Event Sourcing agh! Many people have been getting confused over what CQRS ...
- DDD创始人Eric Vans:要实现DDD原始意图,必须CQRS+Event Sourcing架构
http://www.infoq.com/interviews/Technology-Influences-DDD# 要实现DDD(domain drive design 领域驱动设计)原始意图,必 ...
随机推荐
- 工作经常使用的SQL整理,实战篇(二)
原文:工作经常使用的SQL整理,实战篇(二) 工作经常使用的SQL整理,实战篇,地址一览: 工作经常使用的SQL整理,实战篇(一) 工作经常使用的SQL整理,实战篇(二) 工作经常使用的SQL整理,实 ...
- Linux学习笔记——例说makefile 头文件查找路径
0.前言 从学习C语言開始就慢慢開始接触makefile,查阅了非常多的makefile的资料但总感觉没有真正掌握makefile,假设自己动手写一个makefile总认为非常吃力.所以特意借 ...
- Codeforces Round #191 (Div. 2) D. Block Tower
D. Block Tower time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...
- 瑞丽的SQL-SQL Server的表旋转(行列转换)
所谓表旋转,就是将表的行转换为列,或是将表的列转换为行,这是从SQL Server 2005開始提供的新技术.因此,如果希望使用此功能,须要将数据库的兼容级别设置为90.表旋转在某些方面也是攻克了表的 ...
- FTP文件操作之获取文件列表
前面已经介绍了很多关于FTP对文件的操作,今天再跟大家介绍一个获取文件列表的功能.这个功能应该算是最简单的一个了,它只是获取了一下文件信息,而没有进行实质上的数据传输. 下面是是该功能的核心代码: ...
- linux如何执行后台进程
linux直接执行一个过程.电流指令结束后.或者关闭掉shell形成过程将结束. 如何在后台执行的处理 办法1 采用nohup命令,nohup命令本身的意思no hung up他说,他们将不会收到sh ...
- UML学习(一)类图和对象图
对象是一个概念,一种抽象或者事物.对象能够是具有现实意义的事物,也能够是抽象的一个概念.比方,一家公司或者一个进程. 类是一组对象的集合或者抽象的概念.类具有同样的属性和方法. 介绍完基本对象和类的基 ...
- poj 2182 Lost Cows(段树精英赛的冠军)
主题链接:http://poj.org/problem? id=2182 Lost Cows Time Limit: 1000MS Memory Limit: 65536K Total Submi ...
- Oracle 闪回表实验
工:闪回表实验 1.结构测试表flb_test,数据不小于10000行: TEST_USER1@PROD>create table flb_test(id number,dd date); Ta ...
- 新手学Unity3d的一些网站及相应学习路线
一.unity3d有什么优势 如果您对开发游戏感兴趣,而又没有决定选择哪一个游戏引擎,别犹豫了 unity3d是一个很好的选择! 就我来看unity3d优势主要有以下几方面:首先部署简单,自带了一个I ...