Event Sourcing
Event Sourcing - ENode(二)
接上篇文章继续
http://www.cnblogs.com/dopeter/p/4899721.html
分布式系统
前篇谈到了我们为何要使用分布式系统,因为ENode本身就是一个分布式的框架。看了很多DDD、CQRS的框架,一般情况是一个上下文一个系统,可以多分系统实例进行分布式部署,但需要自己搭配分布式的基础设施。而ENode已经提供了较为完整的分布式DDD解决方案。
1. 分布式通讯基础设施
一般使用RPC、MOM、REST,不过最近REST已经逐渐弱化特别是在一个大系统的内部,或者是对性能要求较高的场景,作者自己实现并开源了MOM组件EQueue作为基础设施搭配ENode,有一些Kfaka的设计理念,但加入了自己的设想,可以到作者的博客上了解了解。
http://www.cnblogs.com/netfocus/category/496012.html
2. 分布式的粒度
这是ENode最大的亮点,从目前业内的发展的大方向来说,也是ENode能被投入生产环境试运行的原因之一。ENode是以Command、Event、Application Message、Exception为基础粒度采用的分布式设计。目前其他的CQRS框架大多都还是系统实例级的分布式,如果要实现这种粒度的分布式,需要自己动手设计,从长远来看,如果真的投入到生产环境,框架升级之后引发的不兼容等问题是很有可能的,当然ENode如果能成为我们目前OLTP系统的流行框架的话,还是得小心以后被作者绑架。
关系数据库
作者在框架中其实一直在使用关系数据库,因为有了前面粒度的铺垫,再加上ES本身的写屏障特性,实现了类似关系数据库的一致性,而只使用了关系数据库的持久化以及检查机制。当然作者在实现中仍然使用了事务,以及将关系数据库当分布式的锁来使用,有点类似ZooKeeper,这些都是基于的是粒度的缩小,所以性能上是有很大的提高。不过这些是作者的默认实现,我们可以自己实现另外一套。
其实应该从Sample开始讲的,不过如果有兴趣的朋友可以直接去下载作者的源码,作者的Sample写的很好,所以直接开剖。
全观

这是ENode的代码。
我们可以认为分为2层,开发者应用层(业务开发人员专用),基础设施层(架构开发人员专用) 。
Commanding,Domain,Eventing,Snapshoting属于应用层。是ES的专用术语。
Infrastructure和Configurations则是基础设施层。
Commanding

我们可以认为这是Commanding的装配图,顾名思义。
ICommand,一个命令

继承了IMessage,这就是前面提到的分布式消息。
其他的接口都是顾名思义。
ICommandHandler 命令处理者
ICommandHandlerProvider 隔离命令处理者的装配
ICommandHandlerProxy 命令处理者代理
Async则是代表异步的
就不一一介绍了。重点是看作者实现的默认的组件。

面向接口是代表作者抽象的高度与角度,真正代表其落地思想的则是其默认实现的类。
内容有点多,而且会很跳跃,这篇是讲不完的,我们还是慢慢来。主要是打字打的有点累了,手跟不上脑。先看看作者实现的DefaultProcessingCommandHandler类,
这是较为核心的,也可以认为是核心处理Command逻辑的类。
它实现了IProcessingMessageHandler接口,这个接口只有一个方法
void HandleAsync(X processingMessage);
于是我们就顺藤摸瓜看看作者的实现。


屏幕太小,截了2张图,第一张没什么特别的,第二张,这里使用了2个不同的Handler,一个是同步的,一个是异步的。它们的逻辑会有一些不同。
当然肯定是会执行Command的处理方法的。区别是什么呢?
在HandleCommand方法中,执行完后,有一些判断Command是否只是修改单个聚合根的逻辑,这里体现的是作者设计思想中的单个聚合根隔离性,也就是前篇所讲的关系数据库中事务隔离性粒度放至聚合根的粒度。在经过验证后,会直接提交Event,准备持久化Event,执行后续的,Event后续再讲。
在ProcessCommand方法中,用到了CommandStore,在作者默认实现的CommandStore中有2种实现方式,InMemory以及SQLSERVER,InMemory中是将Command存储在字典中,SQLSERVER则是以Command的ID作为主键,这里的逻辑是首先去CommandStore中检索是否存在相同ID的Command,如果有,则被证明是执行过了。如果没有,则继续执行Command,Command执行成功后,将Command保存至CommandStore中,保存成功后提交Event,准备持久化Event。这里实际上是在消除Command的幂等,第一个乐观锁机关出现了。
为什么第一个方法不使用乐观锁,而直接发布事件呢。
HandleCommand方法中的Command所对应的聚合根实际上还没有被更新,只是预提交一个Dirty的聚合根数据至EventHandler处,在EventHandler处会再次有乐观锁机关。
为什么ProcessCommand方法中要使用乐观锁呢,其实我没有完全的答案,猜测有以下几点
1. 见上图的If ,else if处,对一个Command来说,是可以有多个Handler的,无论是在系统实例内部或是其他并行的系统实例,再或者是其他上下文的系统实例,都有可能会有同步以及异步处理的Handler。
2. ProcessCommand方法是对应的异步CommandHandler,既然是异步的,作者使用了.NET的Task,虽然一个Command是单线程在跑,不过要是在异步中,例如我们和另外的系统通讯也使用了异步,那么这个线程就会返回,执行下一个Command,如果下一个Command相同,这个理论上是不大可能的。
3. MOM中消息的重复发送,这是有可能出现的。
Event Sourcing的更多相关文章
- 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 ...
- Typed Message模式与Event Sourcing
引言 在<设计模式沉思录>(Pattern Hatching: Design Patterns Applied,[美]JohnVlissides著)一书的第4章中,围绕事件Message传 ...
- DDD创始人Eric Vans:要实现DDD原始意图,必须CQRS+Event Sourcing架构
http://www.infoq.com/interviews/Technology-Influences-DDD# 要实现DDD(domain drive design 领域驱动设计)原始意图,必 ...
- Event Sourcing pattern
Event Sourcing pattern Instead of storing just the current state of the data in a domain, use an app ...
- DDD CQRS和Event Sourcing的案例:足球比赛
在12月11日新的有关DDD CQRS和Event Sourcing演讲:改变心态- 以更加面向对象视角看待业务领域建模中,作者以足球比赛football Match为案例说明传统编程方法和CQRS的 ...
- 事件溯源模式(Event Sourcing Pattern)
此文翻译自msdn,侵删. 原文地址:https://msdn.microsoft.com/en-us/library/dn589792.aspx 本文介绍了一种有利于物化(materialize)领 ...
- [外文理解] DDD创始人Eric Vans:要实现DDD原始意图,必须CQRS+Event Sourcing架构。
原文:http://www.infoq.com/interviews/Technology-Influences-DDD# 要实现DDD(domain drive design 领域驱动设计)原始意 ...
- 1.2 Use Cases中 Event Sourcing官网剖析(博主推荐)
不多说,直接上干货! 一切来源于官网 http://kafka.apache.org/documentation/ Event Sourcing 事件采集 Event sourcing is a st ...
随机推荐
- bootstrap之DumpWindowHierarchy
DumpWindowHierarchy package io.appium.android.bootstrap.handler; import android.os.Environment; impo ...
- java.lang.NullPointerException错误分析
java.lang.NullPointerException是什么错误 你使用了空的指针.在java中虽然号称抛弃了C++中不安全的指针,但其实他所有的东西你都可以理解为指针.这种情况一般发生在你使用 ...
- Java 里把 InputStream 转换成 String 的几种方法
我们在 Java 中经常会碰到如何把 InputStream 转换成 String 的情形,比如从文件或网络得到一个 InputStream,需要转换成字符串输出或赋给别的变量. 未真正关注这个问题之 ...
- Spark1.0.0 属性配置
1:Spark1.0.0属性配置方式 Spark属性提供了大部分应用程序的控制项,而且能够单独为每一个应用程序进行配置. 在Spark1.0.0提供了3种方式的属性配置: Sp ...
- Linux中块设备驱动程序分析
基于<Linux设备驱动程序>书中的sbull程序以对Linux块设备驱动总结分析. 開始之前先来了解这个块设备中的核心数据结构: struct sbull_dev { i ...
- 黄聪:Microsoft Enterprise Library 5.0 系列教程(五) Data Access Application Block
原文:黄聪:Microsoft Enterprise Library 5.0 系列教程(五) Data Access Application Block 企业库数据库访问模块通过抽象工厂模式,允许用户 ...
- HOJ2275 Number sequence
Number sequence My Tags tag=&type=or" style="margin:0px; padding:0px; color:rgb(27,87, ...
- sql server从一个数据库复制一个表到另一个数据库的方法
分两步进行: 第一步,复制表结构: 在表上面右击——>编写表脚本为:——>Create到——>新查询编辑器窗口,你也可以保存为sql文件, 将新查询编辑器窗口最上面的一句话USE [ ...
- unicode下一个,读取数据库乱码问题
TCHAR cbContent[512]; dyn.GetFieldValue(0,cbContent,512); // 中文会显示乱码 AfxMessageBox(cbConte ...
- Android 内存泄漏优化汇总
android内存泄漏优化摘要 博客分类: android android内存溢出OutOfMemoryError . android移动应用程序的内存分配一般是8凯瑟琳约,不正确地假定处理内存处理非 ...