本文是讀完Martin Kleppmann的《Making sense of stream processing》的一些理解和感悟。
Event Sourcing (事件溯源)、Stream processing(流處理)、Complex Event Processing(復雜事件處理)、CQRS(Command Query Responsibility Segregation,命令查詢職責分離)、Event-driven architecture(事件驅動架構)等令人眼花繚亂的技術術語的本質是事件和事件流,這些技術的區別在于對事件的粒度的劃分和對事件處理過程的側重點。
1. Event Sourcing (事件溯源)
Event Sourcing側重于事件的持久化,這里的事件的粒度可以細到對業務數據的增刪改查,如果和傳統的關系型數據庫做對比,傳統的關系型數據庫記錄的數據是一種最終狀態,這個狀態可以被隨時增刪改查,而Event Sourcing記錄的數據則是對狀態進行增刪改的有序命令流,每條數據本省不可被更改,但依據這些命令流可以構造出最終的狀態:
正如Martin所舉的電商購物車的例子,傳統的關系型數據庫表中記錄的是用戶、商品和數量的信息,是最終結果:
而事件溯源則記錄用戶的每一次添加商品、更新數量、提交訂單操作,是有序的命令流:
實現Event Sourcing并不難,Event Store這款開源數據庫就可以幫助我們存儲事件以及進行復雜查詢,還有很多新玩法等著我們去實踐。
2. Stream processing(流處理)
Stream processing側重于事件處理的過程,這里的事件的粒度偏向于實時的業務數據,Martin稱之為Raw Event,如每秒的室內溫度數據、用戶當前發布的微博等,由于數據量大且實時要求高,流處理一般采用分布式架構。基于這些原始事件,可以構建上層的實時統計、聚合的邏輯,從而生成Aggregated Data,當然也可以構建離線分析的邏輯,所以原始事件是實現流處理的基礎,聚合數據只是最終呈現的結果。
近年來隨著Twitter、Facebook等互聯網公司的發展,分布式流式計算逐漸成熟。這些互聯網公司的業務數據有一個共同點,即有大量的并發的讀寫操作,在這種業務場景下傳統的以關系型數據庫為核心的系統架構已經不能勝任,只能將數據讀寫操作分離,構建新的解決方案,保證高可用性和高一致性。分布式流式計算是可以實現讀寫分離的一種架構,也正是讀寫分離讓流處理和事件溯源的產生了邏輯上的內在一致性:在兩種技術中事件在本質上講都是數據的寫操作,或者說是更新操作,流處理中的聚合數據和事件溯源里的狀態及查詢是數據讀操作的結果:
典型的分布式流式計算的架構是這樣的:
關于讀寫分離,Martin在文中還進行了一種有意思的抽象:應用程序里面產生后臺交互的Button對應寫操作,而Screen頁面上展示的的結果對應讀操作,雖然不夠嚴謹但足以能夠說明,事件的范疇在當前的Web端和Mobile端應用程序中已經不僅僅是傳統的交易數據,用戶的每一次點擊動作和瀏覽記錄都是能產生寫操作事件,你打開淘寶的一瞬間,事件就會源源不斷地產生,可謂“買賣未動,數據先行”。
3. Complex Event Processing(復雜事件處理)
CEP同樣側重于事件處理的過程,但是更強調事件之間存在復雜的關系,如時間順序關系/聚合關系/層次關系/依賴關系。CEP需要構建規則引擎,對符合一定Pattern的事件進行查詢和處理。這其中比較優秀的工具有Esper和Flink CEP。
Flink官網的一個簡單案例足以說明復雜事件處理和流處理結合后的威力:數據中心機架的溫度被實時監控,溫度超過閾值時會產生Warning事件,連續兩個Warning事件會產生Alert事件,Alert事件則會觸發降溫的動作,在樣的業務邏輯在Flink平臺上用短短幾行代碼就可以實現,而用普通手段則要復雜得多。CEP可以提高系統的監控和分析能力。
4. CQRS (Command Query Responsibility Segregation,命令查詢職責分離)
CQRS上升到了系統架構這個層次,事件的粒度是系統中的業務數據。在架構層面,將一個系統分為寫入(命令)和查詢兩部分。一個命令表示一種意圖,表示命令系統做什么修改,命令的執行結果通常不需要返回;一個查詢表示向系統查詢數據并返回。同樣是讀寫分離,互聯網場景下的流式計算中的讀寫分離是為了解決高并發讀寫操作,而CQRS中的讀寫分離則是為了解決復雜的數據模型,是Domain Driven Design(領域驅動設計)的實踐。
5. Event-driven architecture(事件驅動架構)
在事件驅動架構中,事件的粒度為多進程、多服務、多系統之間的通信消息。不同于SOA架構,EDA架構是pub-sub模式:Process1處理完邏輯后產生消息,Process2訂閱消息并進行處理, Process1不知道Process2的存在,Process間通過MQ最終數據的最終一致性。
