Event Sourcing - ENode(二)

 

接上篇文章繼續html

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.htmlide

2. 分佈式的粒度性能

這是ENode最大的亮點,從目前業內的發展的大方向來講,也是ENode能被投入生產環境試運行的緣由之一。ENode是以Command、Event、Application Message、Exception爲基礎粒度採用的分佈式設計。目前其餘的CQRS框架大多都仍是系統實例級的分佈式,若是要實現這種粒度的分佈式,須要本身動手設計,從長遠來看,若是真的投入到生產環境,框架升級以後引起的不兼容等問題是頗有可能的,固然ENode若是能成爲咱們目前OLTP系統的流行框架的話,仍是得當心之後被做者綁架。spa

 

關係數據庫線程


 

做者在框架中其實一直在使用關係數據庫,由於有了前面粒度的鋪墊,再加上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中消息的重複發送,這是有可能出現的。

 

關於上面猜想,做者的官方解釋


 

由於聚合根是in-memory的 因此不須要異步處理 而不操做聚合根時基本是調用其餘外部IO接口,因此須要異步 另外,不操做聚合根的命令也必定會有一個關聯的聚合根ID,這是框架的要求 好比轉帳前要求驗證帳號是否合法,多是調用外部接口,但咱們必定知道是要驗證哪一個聚合根的  雖然框架裏目前沒使用這個聚合根ID,但至少cmdstore會記錄下來 方便咱們跟蹤命令和聚合根的可能對應關係 一個cmd概括起來能夠理解爲有兩種目的,1:操做某個聚合根,2:驗證和某個聚合根相關的某種外部邏輯或規則
相關文章
相關標籤/搜索