從架構師思維看分散式事務兩種技術方案 - banq

banq發表於2022-04-29
程式設計師從無到有構建程式碼,應該注重組合思維,做出來的東西需要能夠相互組合在一起;而架構師是從上而下的視角,因為不參與具體細節構建,但為了落地,應該具有多維度多維度視角,從程式設計師到架構師思維轉變很重要。

下面這篇文章談了架構師的多維度視角:

架構師應該多維度多視角地思考 - Gregor

分散式事務為案例,從不同視角看這個問題,得到的解決方案可能不同。

例如如果從狀態角度看分散式事務實現,那麼下面這篇文章也許有啟發:

如何實現跨Mysql、Redis和Mongo分散式事務? - dongfu

但是,如果從微服務和事件驅動角度看分散式事務實現,下面這篇文章也有啟發:

如何設計基於事件驅動架構的銷售庫存微服務?- Jasbir

從架構師思維看分散式事務兩種技術方案 - banq
這兩種實現方案似乎都可以實現基於微服務+資料庫的分散式事務,第一篇文章更加偏向資料庫基礎設施,從冪等性和補償回滾兩個方面來保證跨多資料來源的儲存一致性;而第二篇文章更傾向微服務靠前一些,因為微服務+資料庫架構中,微服務總是先於資料庫呼叫,而觸發呼叫微服務的東西是事件。

也就是說,事件是一個全新視角,而資料庫狀態則是一個傳統觀點,事件和狀態實際是同一個問題的兩個方面,只是角度不同。
因為從資料庫狀態角度出發設計,那麼就要考慮冪等性,因為狀態孤立的,一個狀態是覆蓋前面一個狀態,狀態之間是沒有關係的,那麼就可能當前狀態和前面狀態是同樣的重複的;那麼在接受狀態儲存時可以通過主鍵等新增辦法實現冪等性,冪等性實際類似重複提交問題。

其次,從狀態角度考慮設計,還要考慮狀態退回補償,因為狀態之間沒有關係,所以需要業務程式在整個事務失敗時,將之前已經儲存過的狀態返回到之前狀態。

但是,如果從(領域)事件角度考慮設計,則可能避免上述狀態設計帶來的複雜性,通過引入Conductor開源工作流,能夠原子性地啟動一個任務,通過這個任務再更改另外一個上下文微服務中的儲存狀態:記憶體狀態或資料庫狀態。

這種方式類似主-從複製的方式,總是一個上下文中的狀態為主,其他都監控這個主狀態,一旦有該狀態改變,或有改變主狀態的命令與事件發生,就把這個改變事件作為訊息廣播到所有監控者,所有監控者就同步更新自己的狀態與其一致。

兩種業務實際都屬於一種流程操作:

  1. 使用者現在正在參與促銷活動:他們有餘額,充值話費,促銷活動將贈送商城積分。
  2. 電子商務網站:銷售與倉庫的庫存更新。

上面兩種業務都可以使用微服務+資料庫實現,而且都是跨不同微服務+資料庫的更新狀態,前者使用所謂分散式事務,後者使用主從同步複製,這兩種實現方案實際可以互換到對方業務場合。

當然,最重要的是基於CAP定理 滿足不同的實時性和併發要求。

這裡提第三種解決方案:事件溯源
使用Kafka等開源工作流訊息系統,能夠保證事件的恰好一次傳遞,一系列事件直接儲存起來,事件之間的先後順序關係也儲存起來了,不會相互覆蓋,如果需要獲得當前最新狀態,只要把之前所有事件遍歷一次計算即可,通過stream操作非常方便簡單。

如果上述兩種業務都輔助以事件溯源,系統複雜性雖然提高了,但是可靠性大大增強,發生問題時,問題追蹤得也有依據,類似建設了一套冗餘系統。

相關文章