分佈式事務有多種主流形態,包括:前端
之因此有這麼多形態,是由於任何事情都沒有銀彈,只有最合適當前場景的解決方案。git
這些形態的原理已經在不少文章中進行了剖析,用「分佈式事務」關鍵字就能搜到對應的文章,本文再也不贅述這些形態的原理,並將重點放在如何根據業務選擇對應的分佈式事務形態上。github
這個相信你們都很清楚,在條件容許的狀況下,咱們應該儘量地使用單機事務,由於單機事務裏,無需額外協調其餘數據源,減小了網絡交互時間消耗以及協調時所需的存儲IO消耗,在修改等量業務數據的狀況下,單機事務將會有更高的性能。數據庫
但單機數據庫因爲 業務邏輯解耦等因素進行了數據庫垂直拆分、或者因爲單機數據庫性能壓力等因素進行了數據庫水平拆分以後,數據分佈於多個數據庫,這時若須要對多個數據庫的數據進行協調變動,則須要引入分佈式事務。編程
分佈式事務的模式有不少種,那究竟要怎麼選擇適合業務的模式呢?如下咱們將從使用場景、性能、開發成本這幾個方面進行分析。網絡
基於消息實現的事務適用於分佈式事務的提交或回滾只取決於事務發起方的業務需求,其餘數據源的數據變動跟隨發起方進行的業務場景。框架
舉個例子,假設存在業務規則:某筆訂單成功後,爲用戶加必定的積分。異步
在這條規則裏,管理訂單數據源的服務爲事務發起方,管理積分數據源的服務爲事務跟隨者。分佈式
從這個過程能夠看到,基於消息隊列實現的事務存在如下操做:工具
咱們能夠看到它的總體流程是比較簡單的,同時業務開發工做量也不大:
能夠看到該事務形態過程簡單,性能消耗小,發起方與跟隨方之間的流量峯谷可使用隊列填平,同時業務開發工做量也基本與單機事務沒有差異,都不須要編寫反向的業務邏輯過程。所以基於消息隊列實現的事務是咱們除了單機事務外最優先考慮使用的形態。
可是基於消息實現的事務並不能解決全部的業務場景,例如如下場景:某筆訂單完成時,同時扣掉用戶的現金。
這裏事務發起方是管理訂單庫的服務,但對整個事務是否提交併不能只由訂單服務決定,由於還要確保用戶有足夠的錢,才能完成這筆交易,而這個信息在管理現金的服務裏。這裏咱們能夠引入基於補償實現的事務,其流程以下:
以上這個是正常成功的流程,異常流程須要回滾的話,將額外發送遠程調用到現金服務以加上以前扣掉的金額。
以上流程比基於消息隊列實現的事務的流程要複雜,同時開發的工做量也更多:
能夠看到,該事務流程相對於基於消息實現的分佈式事務更爲複雜,須要額外開發相關的業務回滾方法,也失去了服務間流量削峯填谷的功能。但其僅僅只比基於消息的事務複雜多一點,若不能使用基於消息隊列的最終一致性事務,那麼能夠優先考慮使用基於補償的事務形態。
阿里GTS/fescar本質上也是這補償的編程模型,只不過補償代碼自動生成,無需業務干預,同時接管應用數據源,禁止業務修改處於全局事務狀態中的記錄。所以,其關於讀場景的適用性,可參考補償。但其在寫的適用場景因爲引入了全局事務時的寫鎖,其寫適用性介於 TCC以及補償之間 。
然而基於補償的事務形態也並不是能實現全部的需求,如如下場景:某筆訂單完成時,同時扣掉用戶的現金,但交易未完成,也未被取消時,不能讓客戶看到錢變少了。
這時咱們能夠引入TCC,其流程以下:
以上是正常完成的流程,若爲異常流程,則須要發送遠程調用請求到現金服務,撤銷凍結的金額。
以上流程比基於補償實現的事務的流程要複雜,同時開發的工做量也更多:
TCC其實是最爲複雜的一種狀況,其能處理全部的業務場景,但不管出於性能上的考慮,仍是開發複雜度上的考慮,都應該儘可能避免該類事務。
SAGA能夠看作一個異步的、利用隊列實現的補償事務。
其適用於無需立刻返回業務發起方最終狀態的場景,例如:你的請求已提交,請稍後查詢或留意通知 之類。
將上述補償事務的場景用SAGA改寫,其流程以下:
以上爲成功的流程,若現金服務扣除金額失敗,那麼,最後一步訂單服務將會更新訂單狀態爲失敗。
其業務編碼工做量比補償事務多一點,包括如下內容:
但其相對於補償事務形態有性能上的優點,全部的本地子事務執行過程當中,都無需等待其調用的子事務執行,減小了加鎖的時間,這在事務流程較多較長的業務中性能優點更爲明顯。同時,其利用隊列進行進行通信,具備削峯填谷的做用。
所以該形式適用於不須要同步返回發起方執行最終結果、能夠進行補償、對性能要求較高、不介意額外編碼的業務場景。
但固然SAGA也能夠進行稍微改造,變成與TCC相似、能夠進行資源預留的形態。
其適用於參與者較少,單個本地事務執行時間較少,而且參與者自身可用性很高的場景,不然,其極可能致使性能降低嚴重。
經過分析咱們能夠發現,並不存在一種事務形態能解決全部的問題,咱們須要根據特定的業務場景選擇合適的事務形態。甚至於有時須要混合多種事務形態才能更好的完成目標,如 上面提到的 訂單、積分、錢包混合的場景:訂單的成功與否須要依賴於錢包的餘額,但不依賴於積分的多少,所以能夠混合基於消息的事務形態以加積分 及 基於補償的事務形態以確保扣錢成功,從而獲得一個性能更好,編碼量更少的形態。
然而目前不少框架都專一於某單一方面的事務形態,如TCC單獨一個框架,可靠消息單獨一個框架,SAGA單獨一個框架,他們各自獨立,容易致使如下問題:
爲了解決上面提到的問題,EasyTransaction這個基於Spring的分佈式事務框架,實現了上述除2PC之外的全部事務形態,並提供了統一的使用接口,完美地解決了以上的問題。其主要特性以下:
若各位對ET興趣,能夠到 https://github.com/QNJR-GROUP/EasyTransaction 查看詳細介紹及示例,本文再也不深刻介紹
不一樣業務場景應按需引入不一樣的事務形態,在條件容許的狀況下,我的建議按照以下次序選擇對應的事務形態:
單機事務》基於消息的事務》基於補償的事務》TCC事務
因SAGA事務的形態須要配合較爲明顯的前端業務交互變動,我的建議在單一事務執行過程較長、存在較多子事務,而且沒法使用基於消息的事務形態時使用。