事務 - TCC模式

TCC

githubhtml

在前一篇文章中講到了BASE模式,這種模式能夠應用在單庫or跨庫事務的場景下。事實上BASE模式不只僅侷限於數據庫層面,還能夠應用於分佈式系統,這類分佈式系統最典型的例子就是電商平臺,它們有如下幾個特徵:git

  1. SOA化/微服務化:單體應用拆分紅多個服務。
  2. 數據庫的各類拆分技術的運用:分表、分庫、分區。
  3. 大量NoSQL數據庫的興起。
  4. 應用之間的通訊手段並不是直接讀數據庫:RESTful、RPC、消息中間件等。
  5. 大量跨應用事務的出現。

在這種場景下,2PC(及XA)已經沒法知足需求,由於它:github

  1. 性能低下,2PC協議是阻塞式的。當協調的數據庫愈來愈多時,性能沒法接受。
  2. 沒法水平擴展以提高性能,只能靠垂直擴展(提高硬件)——更快的CPU、更快更大的硬盤、更大更快的內存——可是這樣很貴,而且很容易遇到極限。
  3. 染指其餘數據庫。
  4. 依賴於數據庫是否支持2PC(XA)。

而BASE只解決最後提交的問題,不能解決諸如在上一篇文章中最後提到的如何保證刷卡消費不透支的問題.因而就有人提出了TCC模式(Try、Confirm、Cancel),這一模式在國內因阿里巴巴的推廣而廣爲人知。數據庫

協議介紹

在TCC協議裏,參與的主體分爲兩種:segmentfault

  • 發起方:發起事務的應用。
  • 參與方:執行事務請求,手上握有資源的服務。

而且有三種動做:Try、Confirm、Cancel。架構

TCC是Try、Confirm、Cancel的簡稱,它們分別的職責是:分佈式

  • Try:負責預留資源(好比新建一條狀態=PENDING的訂單),同時也作業務檢查(好比看看餘額是否足夠),簡單來講就是不能預留已經被佔用的資源。
  • Confirm:負責落地所預留的資源(好比扣費、把訂單狀態變成COMPLETED)
  • Cancel:負責撤銷所預留的資源(好比把訂單狀態變成CANCELED)

關於預留資源要多說兩句,資源都是有限的,所以預留資源都是有時效的,若是當預留資源遲遲得不到Confirm——咱們將這種狀況稱爲timeout——參與方會自行將其Cancel(這裏有坑,下面會講)。也就是說參與方對於資源具備自我管理能力,這樣能夠避免因發起方的問題致使資源被長期佔用。微服務

TCC於BASE相比,增長了業務檢查和撤銷事務的功能。性能

同時,TCC將2PC數據庫層面的動做提高到了服務層面,不一樣的是TCC的全部動做都是一個本地事務,每一個本地事務都在動做完成後commit到數據庫:spa

  • Try至關於2PC的Commit request phase,外加了業務檢查邏輯
  • Confirm至關於2PC的Commit phase的commit動做
  • Cancel至關於2PC的Commit phase的rollback動做

流程

如下是TCC的狀態圖:

TCC的狀態

下面是流程步驟(你會發現和2PC很像):

  1. 【發起方】發送Try到全部參與方
  2. 每一個【參與方】執行Try,預留資源
  3. 【發起方】收到全部【參與方】的Try結果
  4. 【發起方】發送Confirm/Cancel到全部參與房
  5. 每一個【參與方】執行Confirm/Cancel
  6. 【發起方】收到全部【參與方】的Confirm/Cancel結果

異常處理

從【發起方】的角度來看出現異常要怎麼處理:

  1. step 1發生異常,【發起方】能夠什麼都不作等待【參與方】自行Cancel,也能夠直接發起Cancel請求
  2. step 二、3發生異常,意味着【發起方】沒有收到【參與方】的響應,這個時候因認定爲失敗,執行Cancel
  3. step 4發生異常,【發起方】重試Confirm/Cancel
  4. step 五、6發生異常,意味着【發起方】沒有收到【參與方】的響應,這個時候因認定爲失敗,重試Confirm/Cancel

從【參與方】角度來看看看出現異常怎麼處理:

  1. step 1,意味着【參與方】沒有收到請求,什麼都不須要作
  2. step 2,意味着【參與方】沒有執行成功,什麼都不須要作
  3. step 3,意味着【發起方】沒有收到結果,什麼都不須要作,等待【發起方】重試便可。【參與方】要保證prepare是冪等的。
  4. step 4,等待【發起方】重試,或者等待timeout後自行Cancel。
  5. step 5,等待【發起方】重試便可
  6. step 6,意味着【發起方】沒有收到結果,什麼都不須要作,等待【發起方】重試便可,【參與方】要保證Confirm/Cancel是冪等的。

觀察一下你就會發現TCC和2PC存在同樣的問題:

  1. 若【發起方】/【參與方】因崩潰遺失了信息,則會形成有的【參與方】已Confirm,有的【參與方】則被Cancel了,甚至於依然保持在預留狀態。
  2. 若【發起方】在step 4發送Confirm,而【參與方】在Cancel(因timeout致使)。

不過TCC在處理這種狀況相比2PC具備一些優點,由於TCC是在服務層面的,當出現這種問題的時候能夠很容易經過日誌、業務數據排查出來,而後人工介入,而2PC徹底是數據庫底層的。

對於ACID的保證

TCC對於ACID的保證:

  • A,正常狀況下保證
  • C,在某個時間點,會出現A庫和B庫的數據違反一致性要求的狀況,可是最終是一致的
  • I,在某個時間點,A事務可以讀到B事務部分提交的結果
  • D,和本地事務同樣,只要commit則數據被持久

實現TCC時的注意事項

實現TCC須要關注如下幾個方面:

  • TCC模式在於服務層面而非數據庫層面
  • TCC模式依賴於各服務正確實現Try、Confirm、Cancel和timeout處理機制
  • TCC模式最少通訊次數爲2n(n=服務數量)
  • 不是全部業務模型都適合使用TCC,好比發郵件業務根本就不須要預留資源
  • 須要良好地設計服務的日誌、人工處理流程/機制,便於異常狀況的處理

參考資料

相關文章
相關標籤/搜索