CQRS,中文翻譯命令和查詢職責分離,它是一種架構,不只能夠從數據庫層面實現讀寫分離,在代碼層面上也是推薦讀寫分離的。在接口上能夠更爲簡單html
命令端定義git
ICommandResult Execute(ICommand command)github
查詢端定義數據庫
IQueryResult Fetch(IQuery query)服務器
它的好處是CQ每端對外只有一個接口,職責單一。帶來的不便就是要定義好多命令(Command)和查詢(Query)對象。但相比定義好多個接口我的以爲仍是這樣的方式更好。架構
CQRS不是一個特別炫麗的架構,我以爲他更多的是爲了解決數據顯示的複雜性。在實際項目中,每每是要查詢的數據很是複雜和多樣性(也許你並不認同),這樣就能夠針對查詢定義相對須要的ReadModel,也能夠設計多個有針對性的讀庫。併發
當咱們的應用程序開發完以後就須要發佈部署了,在部署以前你的應用程序須要有個宿主能夠對外提供服務,它能夠是WebService,Wcf,WebApi等等。負載均衡
單機是一個最簡單的部署方式,優勢是維護和部署起來很方便, 缺點是一旦宕機你的整個服務將不可用,處理能力有限,更新應用程序可能要中止服務。異步
最簡單的方式是部署多個單機,利用DNS輪詢就能夠實現簡單的負載均衡,這種方案的缺點就是存在會話丟失,這是由於上一次的會話是在服務器1上,可能下一次的會話DNS就會將域名指向服務器2上,能夠採用Cookie或者其餘方案解決這一問題。還有就是這一集羣方式在處理併發上難度較大,固然也能夠採用樂觀鎖和數據庫的悲觀鎖機制,不過這會帶來性能問題。分佈式
上圖只是對單機集羣的一種擴展,Connection Manager負責管理與客戶端的鏈接及請求,而後將具體的命令和查詢轉發到具體的Server,以達到負載均衡的目的,同時它能夠將處理相同命令的請求路由到同一個服務器上,能夠初步解決併發問題。這種方案也有點相似ngixn,缺點就是帶寬壓力較大
上圖的部署方式將命令和查詢服務嚴格區分開來,利用消息隊列達到流量削鋒、應用解藕和異步處理的目的。命令服務接收到命令後將其發送到Kafka,將相同類型的命令發送到同一topic中,再根據Key分發到不一樣的partition上,利用Kafka的Rebalance動態添加消費服務,這樣的話就能夠當請求過多時增長服務,閒時減小服務,很是靈活。
我的以爲這樣的部署有相似微服務,在此基礎上還能夠分離出ValidationService和AuthenticationService等,如CommandService接收到命令後經過驗證服務後再發送到Kafka中,同時也是將軟件層面的AOP替換成服務層面,每一個CommandConsumer像是一個黑盒,外部沒法訪問。
簡單的示例能夠參考 https://github.com/imyounghan/umizoo/tree/master/src/Samples
上圖是對圖2和圖3的一個整合,利用了各自的優勢。還有一種方案就是Connection Manager提供給客戶端一個可用的CommandService或QueryService與客戶端進行直連,這樣能夠避免全部的請求都要通過Connection Manager,減輕Connection Manager的帶寬壓力,能夠參照P2P的思路。
採用了分佈式後會致使服務增多,問題也會增多,管理起來也會變得複雜,能夠藉助Zookeeper來管理監控這些服務。總之分佈式狀況下要考慮的問題會有不少,本文也無逐一續清,須要掌握的知識點也較多。