微服務設計—事件驅動架構

在Monolithic系統中所有應用共享一個資料庫,通過使用關係型資料庫能夠自然的帶來ACID特性。

- Atomicity(原子性):一個事務中的操作是原子的,其中任何一步失敗,系統都能夠完全回到事務前的狀態

- Consistency(一致性):資料庫的狀態始終保持一致

- Isolation(隔離性):多個並發執行的事務不會互相影響

- Durability(持久性):事務處理結束後,對數據的修改是永久的

但在微服務架構下,每個微服務使用獨立的資料庫,要具備ACID特性就需要採用更加複雜的手段。通常在微服務架構下我們會選擇高可用的目標,因此我們一般會選擇最終一致性為目標。通過下面的示例,我們來了解一下如何通過事件驅動架構達成此目標。

通過事件保證最終一致性

我們假設一個系統中有交易和賬戶兩個微服務,在進行購物時需要新增一個交易記錄,並減少賬戶賬戶金額。兩個微服務可通過以下方式完成交易:

  1. 交易服務在資料庫中增加一條交易記錄,並記錄交易結果RESULT欄位為等待狀態
  2. 交易服務通過消息隊列發布交易事件,此事件由賬戶服務訂閱,因此賬戶服務會收到此事件
  3. 帳戶服務收到事件後對賬戶餘額進行檢查,並在檢查通過後修改資料庫中的帳戶餘額
  4. 帳戶服務發布帳戶餘額變更事件,交易服務收到此事件
  5. 交易服務根據事件的結果(成功或失敗)修改交易記錄的結果RESULT欄位

說明:為降低複雜度,這裡僅考慮交易服務根據帳戶服務的操作結果正確更新交易狀態,忽略交易最終失敗帳戶金額回滾的步驟。後面所有的示例也是如此。

通過事件表保證原子性

以上的步驟中還存在非原子性的問題。比如第3、4這兩個步驟,如果賬戶服務執行完第3步後崩潰了,結果帳戶變更事件沒有發布出來,會導致交易服務無法獲得帳戶的修改結果而服務狀態異常。因此必須要保證第3、4兩步的原子性,才能夠保證交易的正確執行。通過在帳戶服務中增加事件表及事件發布器可以解決此問題:

增加事件表保證原子性

  1. 帳戶服務在收到交易事件後,通過事務修改帳戶表並在事件表中插入事件
  2. 事件發布器通過定時任務查詢事件表,將查詢到的事件發布出去

此方案比較簡單,但要求在微服務對應的資料庫中,必須增加事件表,且服務的業務代碼中必須要同時操作業務表和事件表,一旦遺漏了事件表就會出現問題。

提取資料庫事務日誌發布事件

另一個方案是通過提取器直接對資料庫中的事務日誌進行提取,並根據數據表的修改發布事件。當前有一些開源項目提供了資料庫事務日誌的提取能力。採用此方案可以簡化業務的開發。

提取事務日誌發布事件

基於Event Sourcing

除了以上方案,還可以採用Event Sourcing達成我們的目標。Event Sourcing採用類似資料庫的事務日誌的方式,將所有對象的狀態變更記錄在事件庫中,並通過API支持應用訂閱和查詢事件。因此通過事件庫中的事件序列,可以獲知系統中對象狀態的變更。

基於Event Sourcing解決最終一致性

  1. 帳戶服務和交易服務分別向事件庫訂閱交易事件和帳戶事件
  2. 交易服務發起交易,會在事件庫中生成「發起交易」事件
  3. 帳戶服務收到此事件後,在金額條件滿足的情況下,生成「帳戶金額變更」事件
  4. 交易服務收到此事件後,確定交易成功,發布交易成功事件

使用Event Sourcing方案的好處是事件即狀態,事件庫中的事件可以保證原子性,且可以通過事件回溯系統中對象狀態的變更過程。

但帶來的問題是事件庫要保證高性能和高可靠,這增加了系統的成本。

總結

微服務架構下要保證跨微服務的數據一致性,將無法直接利用關係型資料庫提供的ACID機制,因此需要引入事件驅動架構解決此問題。為解決資料庫修改和發布事件時的原子性,微服務可以採用增加事件表或提取資料庫事務日誌的方式,也可以採用Event Sourcing的方案。

參考資料

Event-Driven Data Management for Microservices

微服務架構之事件驅動架構 - CSDN博客

系列主題

微服務的定義和優缺點

微服務設計模式—API Gateway

微服務設計模式—服務註冊與發現

微服務設計模式—微服務通信

微服務設計—微服務可靠性

微服務設計—微服務部署

微服務設計—將Monolithic重構為微服務

微服務設計—事件驅動架構


推薦閱讀:

《Cloud Native Go》筆記(十五)結論
《微服務設計》閱讀筆記(九)安全
「演講復盤」技術沙龍(滬江網4月) - 我所遇見的微服務演進這十年
微服務落地第三課-Spring Cloud Config Client搭建
如何應對線上故障

TAG:微服務架構 | 軟體設計 |