微服務架構如今很熱,處處能夠看到各大互聯網公司的微服務實踐的分享總結。可是,我今天的分享和微服務沒有關係,但願能夠帶給你們一些新的東西。數據庫
若是必定要說微服務和CQRS架構的關係,那我以爲微服務是一種邊界思惟,微服務的目的是爲了從業務角度拆分(職責分離)當前業務領域的不一樣業務模塊到不一樣的服務,每一個微服務之間的數據徹底獨立,它們之間的交互能夠經過SOA RPC調用(耦合比較高),也能夠經過EDA 消息驅動(耦合比較低)。架構
微服務架構和CQRS架構的關係:每一個微服務內部,咱們能夠用CQRS/ES架構來實現,也能夠用傳統三次架構來實現。併發
首先,咱們須要先理解DDD中的聚合、聚合根這兩個概念。負載均衡
聚合,它經過定義對象之間清晰的所屬關係和邊界來實現領域模型的內聚,並避免了錯綜複雜的難以維護的對象關係網的造成。聚合定義了一組具備內聚關係的相關對象的集合,咱們把聚合看做是一個修改數據的最小原子單元。框架
聚合根,每一個聚合都有一個根對象,根對象管理聚合內的其餘子對象(實體、值對象);聚合之間的交互都是經過聚合根來交互,不能繞過聚合根去直接和聚合下的子實體進行交互。異步
上面的例子中,Car、Wheel、Position、Tire四個對象構成一個聚合,其中Car是聚合根;Customer也是聚合根,Customer不能直接訪問Car下的Tire(子實體),而是隻能經過聚合根Car來訪問。分佈式
上面表達了一個關於聚合的一致性設計原則:聚合內的數據修改,是ACID強一致性的;跨聚合的數據修改,是最終一致性的。遵照這個原則,可讓咱們最大化的下降併發衝突,從而最大化的提升整個系統的吞吐。微服務
In-Memory的意思是指整個系統中的全部的聚合根對象都活在內存。而不是像咱們平時那樣,用到的時候才從DB獲取對象,而後再作修改,再保存回去。線程
在In-Memory的架構下,當要修改某個聚合根的狀態時,它已經在內存,咱們能夠直接拿到該對象的引用,且框架會盡可能保證聚合根對象的狀態就是最新的。聚合根是在內存中的最小計算單元,每一個聚合內部都封裝了業務規則,並保證數據的強一致性。設計
上圖我是挪用了以前比較或的LMAX架構中的一個圖,表達的思想就是in-memory架構。其中Business Logic Processor就是中央業務邏輯處理器,內部承載了大量在機器內存中活着的聚合根對象;
不保存對象的最新狀態,而是保存對象產生的全部事件;
經過事件溯源(Event Sourcing,ES)獲得對象最新狀態;
接下來,咱們再來看一下什麼是事件溯源。
一個對象從建立開始到消亡會經歷不少事件,之前咱們是在每次對象參與完一個業務動做後把對象的最新狀態持久化保存到數據庫中,也就是說咱們的數據庫中的數據是反映了對象的當前最新的狀態。而事件溯源則相反,不是保存對象的最新狀態,而是保存這個對象所經歷的每一個事件,全部的由對象產生的事件會按照時間前後順序有序的存放在數據庫中。能夠看出,事件溯源的這種作法是更符合事實觀的,由於它完整的描述了對象的整個生命週期過程當中所經歷的全部事件。
那麼,事件到底如何影響一個領域對象的狀態的呢?很簡單,當咱們在觸發某個領域對象的某個行爲時,該領域對象會先產生一個事件,而後該對象本身響應該事件並更新其本身的狀態,同時咱們還會持久化在該對象上所發生的每個事件;這樣當咱們要從新獲得該對象的最新狀態時,只要先建立一個空的對象,而後將和該對象相關的全部事件按照事件發生前後順序從先到後再所有應用一遍便可還原獲得該對象的最新狀態,這個過程就是所謂的事件溯源。
另外一方面,由於是用事件來表示對象的狀態,而事件是隻會增長不會修改。這就能讓數據庫裏的表示對象的數據很是穩定,不可能存在DELETE或UPDATE等操做。由於一個事件就是表示一個事實,事實是不能被磨滅或修改的。這種特性可讓領域模型很是穩定,在數據庫級別不會產生併發更新同一條數據的問題。
CRUD:DB的記錄可變,能夠增刪改查
ES:沒有更新、刪除,只有Append Event,不可變
經過上面這個圖,你們應該能夠更直觀的理解事件溯源和傳統CRUD思想的區別
Actor模型,這個概念你們應該都瞭解。Actor模型的核心思想是:
對象直接不會直接調用來通訊,而是經過發消息來通訊。
每一個Actor都有一個Mailbox,它收到的全部的消息都會先放入Mailbox中,而後Actor內部單線程處理Mailbox中的消息。從而保證對同一個Actor的任何消息的處理,都是線性的,無併發衝突。從全局上來看,就是整個系統中,有不少的Actor,每一個Actor都在處理本身Mailbox中的消息,Actor之間經過發消息來通訊。
Akka框架就是實現Actor模型的並行開發框架,而且Akka框架融入了聚合、In-Memory、Event Sourcing這些概念。
Actor很是適合做爲DDD聚合根。Actor的狀態修改是由事件驅動的,事件被持久化起來,而後經過Event Sourcing的技術,還原特定Actor的最新狀態到內存。
上圖表達的是事件驅動的架構的思想。Node表示節點,每一個節點負責處理邏輯;Event表示消息,節點之間經過消息進行通訊。消息經過分佈式消息隊列如RocketMQ,Equeue進行通訊。
不一樣於SOA架構,EDA架構是pub-sub模式;Node1處理完邏輯後產生消息,Node2訂閱消息並進行處理,Node1不知道Node2的存在;
最終一致性原則,Node1,Node2之間的數據一致性經過MQ最終保證一致;
如何保證最終一致性(消息鏈不會斷開):
A. MQ保證消息不丟;
B. 任何一個Node要保證本身徹底處理完後才發送ACK給MQ;
C. 每一個Node作到對任何消息處理的冪等性;
整個架構具備全部分佈式MQ所帶來的優勢:如異步解耦、削峯、下降整個系統的總體部署成本;
上圖是一個面向Topic的分佈式MQ的邏輯架構圖,採用這種架構的MQ有:Kafka,RocketMQ,EQueue。
Producer發送消息到某個Topic的某個Queue;
消息都存儲在Broker上;
Consumer從Broker拉取消息進行消費,並支持消費者負載均衡;