Event Sourcing在分散式系統中應用
因為國際客戶的存在,我們開始探索如何基於Event Sourcing分佈化應用,主要驅動原因是地理位置距離的原因(稱為sites站點),從不同地理位置訪問應用應該有低延遲,每個站點site應該在最近的資料中心執行應用,應用資料應當跨所有sites複製,每個站點如果存在內部網路分割槽情況下應保持寫入的可用性,當分割槽修復後,從不同站點的更新應該能融合merge,衝突應該能自己解決。
Eventuate是這個專案的原型,繼續不斷完善推向生產環境。
這個案例中有6個站點,(A-F),以不同程式執行在本地localhost,透過改變配置,站點也可以分佈到多個主機上,站點A-F可透過雙向連線 非同步的事件複製連線:
A E \ / C -- D / \ B F <p class="indent"> |
每個站點都必須配置:
1. 一個Akka Remoting 的hostname和port (akka.remote.netty.tcp.hostname 和akka.remote.netty.tcp.port)
2. 本地事件日誌複製的id(log.id 是站點的id)
3.到其他站點的複製連線列表(log.connections)
對於這個案例,site C配置如下:
akka.remote.netty.tcp.hostname = "127.0.0.1"
akka.remote.netty.tcp.port=2554
log.id = "C"
log.connections = ["127.0.0.1:2552", "127.0.0.1:2553", "127.0.0.1:2555"]
開始這個原型時,我們使用了akka-persistence,但是不久發現 akka-persistence (2.3.8)並不適合我們的概念和技術要求,於是決定對 akka-persistence API 進行一些修改結合我們的geo-replication。這些擴充不僅能適用geo-replication場合,而且可克服akka-persistence一些當前限制,比如event-sourced actor必須是叢集範圍內的單例,而我們的目標是,允許幾個actor例項在多個節點併發更新,如果衝突發生也能解決,這樣我們就支援來自幾個事件生產者的事件聚合與匯聚,這樣能確定地對所有這些事件進行重放。
在我們上面原型中 geo-replicated event-source應用是跨站點分佈,每個站點在一個獨立的資料中心,為了低延遲訪問,使用者選擇與其地理位置最近的一個站點互動訪問。
事件日誌
系統核心是全域性可複製的事件日誌,它擁有事件的happens-before關係,它是使用向量vector時間戳來跟蹤的,這些時間戳是由一個或更多向量時鐘vector clock在每個站點產生,並與事件一起儲存到事件日誌中,透過比較向量時間戳,一個站點可決定任何兩個事件的happens-before前後關係或同時發生。見這個案例原始碼
事件的部分順序是由向量時間戳決定的,儲存在每個本地日誌,如果e1 -> e2,那麼offset(e1) < offset(e2),這裡->表示happens-before關係,而offset(e)事件e的在事件日誌中的位置或索引,舉例,如果一個站點A寫入事件e1引起站點B的事件e2,那麼複製協議確保e1總是在所有站點本地日誌儲存中先於e2儲存。
儲存順序很重要,事件的生產和消費者才能從事件日誌獲得可靠複製,引起相應順序事件廣播,如果emit(e1) -> emit(e2),那麼在所有站點所有應用將消費e1先於e2,這裡->是happens-before 關係,emit(e)代表事件的寫入發生,儲存因果順序非常重要。
狀態複製
透過複製日誌記錄,應用狀態能夠在不同站點重新建立,在站點網路分割槽中,站點必須保留狀態更新和複製的可用性,因此,如果發現衝突,必須解決,更準確說,在內部站點網路分割槽中,衝突的更新不會發生。
舉例,站點A對領域物件x1做了更新,那麼更新事件e1被寫入事件日誌,一段時間後,站點A接受到來自站點B的更新事件e2,針對同樣領域物件x1,如果站點B在發射e2事件之前已經處理了e1,那麼e2因果關係是依賴e1,那麼站點A只是簡單將e2更新應用到x1,在這種情況下,兩個更新e1和e1都已經被應用到兩個站點的x1上,而x1的複製也會變成同樣值,另外一個方面,如果站點B與站點A同時更新x1,那麼衝突就發生。
同時發生事件是否衝突完全取決於應用邏輯,例如針對不同領域物件同時修改對於一個應用也許是可接受的,而針對同一個領域物件的同時修改會被看成是衝突,必須解決,任何兩個事件是同時或 happens-before前後順序關係都能透過比較它們的向量時鐘獲得。
衝突解決
如果應用狀態是使用 commutative replicated data types (CmRDTs) 建模的,狀態更新操作是透過事件複製的,併發修改一點不是問題,在這種情況下,事件複製甚至不需要保留因果順序,我們應用中許多狀態更新操作不是滿足互動律commutative 的,我們需要支援衝突解決的互動式和自動化兩個方式。
應用狀態衝突版本在一個同時併發版本樹中被跟蹤,這是一個根據事件的向量時鐘構建的資料結構,對於任何型別s的狀態值和任何型別A的更新,併發版本s能以資料型別
ConcurrentVersions[S, A]方式被跟蹤,併發版本能針對不同領域物件甚至領域物件欄位獨立跟蹤,這依賴於應用需要發現和解決衝突的粒度。
在互動式衝突解決中,一個使用者選擇一個衝突版本作為"winner",這種選擇是作為一個明確的衝突解決事件儲存到事件日誌中,這樣以後使用者互動介入時需要事件重放,這樣可能會進行人工干預下的衝突事件融合merge,這種情況下,衝突解決事件必須包含融合細節以便融合本身也可重新再來一次。
在自動化衝突解決下,為了選擇一個"winner",應用一個定製的衝突解決函式到衝突版本(vector clock演算法?),衝突解決函式會自動融合衝突版本,然後我們就進行了convergent replicated data types (CvRDTs).
注:按照CAP定理,CRDT是保證了可用性A和分割槽性P(AP),實現最終一致性;而Cassandro代表的Paxos是保證強一致性C和分割槽性P(CP)。
相關文章
- 大型分散式網站架構:快取在分散式系統中的應用分散式網站架構快取
- Alluxio在多級分散式快取系統中的應用UX分散式快取
- Apache Kafka不適用於Event Sourcing!ApacheKafka
- 分散式應用追蹤系統 - Skywalking分散式
- DAPP——分散式應用系統開發分析APP分散式
- Event Sourcing落地與意義
- 分散式系統2:分散式系統中的時鐘分散式
- 分散式系統–>(關於系統應用的基本概念)分散式
- 一致性雜湊演算法及其在分散式系統中的應用演算法分散式
- 嵌入式核心板在麻醉系統中的應用
- 分散式KVM坐席協作管控 無壓損分散式坐席在中石油資訊系統整合應用分散式
- 一條SQL在 MaxCompute 分散式系統中的旅程SQL分散式
- CQRS & Event Sourcing — 解決檢索應用程式狀態問題的一劑良方
- 民生銀行牛新莊:大資料及分散式技術在銀行系統中實踐應用大資料分散式
- alpakka-kafka(9)-kafka在分散式運算中的應用Kafka分散式
- MySQL的事件溯源Event Sourcing表結構MySql事件
- AutoML 在推薦系統中的應用TOML
- 分散式系統中ID的需求分散式
- 分散式系統分散式
- 分散式系統中的分散式鏈路追蹤與分散式呼叫鏈路分散式
- 分散式系統:系統模型分散式模型
- 22 | 雜湊演算法(下):雜湊演算法在分散式系統中有哪些應用?演算法分散式
- 模板與例項在系統中的應用
- akka-typed(10) - event-sourcing, CQRS實戰
- WIX是如何從CRUD轉換到Event Sourcing?
- 分散式 - 分散式系統的特點分散式
- 分散式系統(三)——分散式事務分散式
- 騰訊雲分散式資料庫TDSQL在銀行傳統核心系統中的應用實踐分散式資料庫SQL
- 在一個成熟的分散式系統中 如何下手做高可用?分散式
- 嵌入式在電子價籤系統的應用
- Redis 應用-分散式鎖Redis分散式
- [分散式]分散式計算系統淺析分散式
- TiDB 在量化派風控系統中的應用TiDB
- 小乾貨~ NFS在Linux系統中的應用NFSLinux
- 淺談OA系統在應用中安全性
- FMEA在安防技術系統中的應用
- 沒有理由在分散式系統中反對冗餘 (馬克)分散式
- 分散式系統中的事務問題分散式
- 分散式系統中的CAP、ACID、BASE概念分散式