各類分佈式事務的實現方式適用的場景

1、事務和分佈式事務

單機事務咱們常常看到,分佈式事務,通俗點將,就是須要在各個機器上跑的事務,可是事務的每一步都不知道其餘步是否成功,可是在業務上又要保證,全部的步驟,要麼都成功,要麼都不成功。spring

分佈式事務實現的方式(乾貨

  1. 基於消息實現的分佈式事務
  2. 基於補償實現的分佈式事務(gts/fescar自動補償的形式)
  3. 基於TCC實現的分佈式事務
  4. 基於SAGA實現的分佈式事務
  5. 基於2PC實現的分佈式事務

什麼時候使用單機事務

這個相信你們都很清楚,在條件容許的狀況下,咱們應該儘量地使用單機事務,由於單機事務裏,無需額外協調其餘數據源,減小了網絡交互時間消耗以及協調時所需的存儲IO消耗,在修改等量業務數據的狀況下,單機事務將會有更高的性能。編程

什麼時候選擇基於消息實現的事務?

基於消息實現的事務適用於分佈式事務的提交或回滾只取決於事務發起方的業務需求,其餘數據源的數據變動跟隨發起方進行的業務場景。網絡

舉個例子,假設存在業務規則:某筆訂單成功後,爲用戶加必定的積分。框架

在這條規則裏,管理訂單數據源的服務爲事務發起方,管理積分數據源的服務爲事務跟隨者。異步

從這個過程能夠看到,基於消息隊列實現的事務存在如下操做:分佈式

訂單服務建立訂單,提交本地事務 訂單服務發佈一條消息 積分服務收到消息後加積分 咱們能夠看到它的總體流程是比較簡單的,同時業務開發工做量也不大:工具

編寫訂單服務裏訂單建立的邏輯 編寫積分服務裏增長積分的邏輯 能夠看到該事務形態過程簡單,性能消耗小,發起方與跟隨方之間的流量峯谷可使用隊列填平,同時業務開發工做量也基本與單機事務沒有差異,都不須要編寫反向的業務邏輯過程。所以基於消息隊列實現的事務是咱們除了單機事務外最優先考慮使用的形態。性能

可是如何保證消息的可靠性,是須要咱們處理的。 你們能夠看一下這篇文章,: 【spring cloud實現可靠消息一致性】。這位兄弟已經寫的很詳細了,我就不細說了測試

什麼時候選擇利用補償實現的事務?

可是基於消息實現的事務並不能解決全部的業務場景,例如如下場景:某筆訂單完成時,同時扣掉用戶的現金編碼

這裏事務發起方是管理訂單庫的服務,但對整個事務是否提交併不能只由訂單服務決定,由於還要確保用戶有足夠的錢,才能完成這筆交易,而這個信息在管理現金的服務裏。這裏咱們能夠引入基於補償實現的事務,其流程以下:

建立訂單數據,但暫不提交本地事務 訂單服務發送遠程調用到現金服務,以扣除對應的金額 上述步驟成功後提交訂單庫的事務 以上這個是正常成功的流程,異常流程須要回滾的話,將額外發送遠程調用到現金服務以加上以前扣掉的金額。

以上流程比基於消息隊列實現的事務的流程要複雜,同時開發的工做量也更多:

編寫訂單服務裏建立訂單的邏輯 編寫現金服務里扣錢的邏輯 編寫現金服務裏補償返還的邏輯 能夠看到,該事務流程相對於基於消息實現的分佈式事務更爲複雜,須要額外開發相關的業務回滾方法,也失去了服務間流量削峯填谷的功能。但其僅僅只比基於消息的事務複雜多一點,若不能使用基於消息隊列的最終一致性事務,那麼能夠優先考慮使用基於補償的事務形態。

阿里GTS/fescar本質上也是這補償的編程模型,只不過補償代碼自動生成,無需業務干預,同時接管應用數據源,禁止業務修改處於全局事務狀態中的記錄。所以,其關於讀場景的適用性,可參考補償。但其在寫的適用場景因爲引入了全局事務時的寫鎖,其寫適用性介於 TCC以及補償之間 。

什麼時候選擇利用TCC實現的事務

然而基於補償的事務形態也並不是能實現全部的需求,如如下場景:某筆訂單完成時,同時扣掉用戶的現金,但交易未完成,也未被取消時,不能讓客戶看到錢變少了。

這時咱們能夠引入TCC,其流程以下:

訂單服務建立訂單 訂單服務發送遠程調用到現金服務,凍結客戶的現金 提交訂單服務數據 訂單服務發送遠程調用到現金服務,扣除客戶凍結的現金 以上是正常完成的流程,若爲異常流程,則須要發送遠程調用請求到現金服務,撤銷凍結的金額。

以上流程比基於補償實現的事務的流程要複雜,同時開發的工做量也更多:

訂單服務編寫建立訂單的邏輯 現金服務編寫凍結現金的邏輯 現金服務編寫扣除現金的邏輯 現金服務編寫解凍現金的邏輯 TCC其實是最爲複雜的一種狀況,其能處理全部的業務場景,但不管出於性能上的考慮,仍是開發複雜度上的考慮,都應該儘可能避免該類事務。 因此咱們開發了TCC框架,來對應大多數的業務場景,下一篇寫一下TCC

什麼時候選擇利用SAGA實現的事務?

SAGA能夠看作一個異步的、利用隊列實現的補償事務。

其適用於無需立刻返回業務發起方最終狀態的場景,例如:你的請求已提交,請稍後查詢或留意通知 之類。

將上述補償事務的場景用SAGA改寫,其流程以下:

訂單服務建立最終狀態未知的訂單記錄,並提交事務 現金服務扣除所需的金額,並提交事務 訂單服務更新訂單狀態爲成功,並提交事務 以上爲成功的流程,若現金服務扣除金額失敗,那麼,最後一步訂單服務將會更新訂單狀態爲失敗。

其業務編碼工做量比補償事務多一點,包括如下內容:

訂單服務建立初始訂單的邏輯 訂單服務確認訂單成功的邏輯 訂單服務確認訂單失敗的邏輯 現金服務扣除現金的邏輯 現金服務補償返回現金的邏輯 但其相對於補償事務形態有性能上的優點,全部的本地子事務執行過程當中,都無需等待其調用的子事務執行,減小了加鎖的時間,這在事務流程較多較長的業務中性能優點更爲明顯。同時,其利用隊列進行進行通信,具備削峯填谷的做用。

所以該形式適用於不須要同步返回發起方執行最終結果、能夠進行補償、對性能要求較高、不介意額外編碼的業務場景。

但固然SAGA也能夠進行稍微改造,變成與TCC相似、能夠進行資源預留的形態。

2PC事務

其適用於參與者較少,單個本地事務執行時間較少,而且參與者自身可用性很高的場景,不然,其極可能致使性能降低嚴重。

並不是一種事務形態就能打遍天下 經過分析咱們能夠發現,並不存在一種事務形態能解決全部的問題,咱們須要根據特定的業務場景選擇合適的事務形態。甚至於有時須要混合多種事務形態才能更好的完成目標,如 上面提到的 訂單、積分、錢包混合的場景:訂單的成功與否須要依賴於錢包的餘額,但不依賴於積分的多少,所以能夠混合基於消息的事務形態以加積分 及 基於補償的事務形態以確保扣錢成功,從而獲得一個性能更好,編碼量更少的形態。

然而目前不少框架都專一於某單一方面的事務形態,如TCC單獨一個框架,可靠消息單獨一個框架,SAGA單獨一個框架,他們各自獨立,容易致使如下問題:

因爲前期只採用了其中一種類型事務的框架,由於工具目前只有錘子,引入其餘工具又涉及測試、閱讀代碼等過程,所以把全部問題都看作釘子,致使性能偏低或者實現不夠優雅 因爲不一樣框架管理事務的形態可能不一致,致使不能很好的協調工做,如某一個TCC框架和另外一個基於消息的事務框架沒法很好融合。

總結

不一樣業務場景應按需引入不一樣的事務形態。

相關文章
相關標籤/搜索