分佈式事務 Seata Saga 模式首秀以及三種模式詳解 | Meetup#3 回顧

做者:屹遠(陳龍),螞蟻金服分佈式事務核心研發 。 本文根據 8月11日 SOFA Meetup#3 廣州站 《分佈式事務 Seata 及其三種模式詳解》主題分享整理,着重分享分佈式事務產生的背景、理論基礎,以及 Seata 分佈式事務的原理以及三種模式(AT、TCC、Saga)的分佈式事務實現。git

本次分享的視頻回顧以及 PPT 查看地址:tech.antfin.com/community/a…github

分佈式事務 Seata 三種模式詳解

1、分佈式事務產生的背景

1.1 分佈式架構演進之 - 數據庫的水平拆分

螞蟻金服的業務數據庫起初是單庫單表,但隨着業務數據規模的快速發展,數據量愈來愈大,單庫單表逐漸成爲瓶頸。因此咱們對數據庫進行了水平拆分,將原單庫單表拆分紅數據庫分片。數據庫

以下圖所示,分庫分表以後,原來在一個數據庫上就能完成的寫操做,可能就會跨多個數據庫,這就產生了跨數據庫事務問題。json

數據庫的水平拆分

1.2 分佈式架構演進之 - 業務服務化拆分

在業務發展初期,「一塊大餅」的單業務系統架構,能知足基本的業務需求。可是隨着業務的快速發展,系統的訪問量和業務複雜程度都在快速增加,單系統架構逐漸成爲業務發展瓶頸,解決業務系統的高耦合、可伸縮問題的需求愈來愈強烈。網絡

以下圖所示,螞蟻金服按照面向服務架構(SOA)的設計原則,將單業務系統拆分紅多個業務系統,下降了各系統之間的耦合度,使不一樣的業務系統專一於自身業務,更有利於業務的發展和系統容量的伸縮。架構

業務服務化拆分

業務系統按照服務拆分以後,一個完整的業務每每須要調用多個服務,如何保證多個服務間的數據一致性成爲一個難題。併發

2、分佈式事務理論基礎

2.1 兩階段提交協議

兩階段提交協議

兩階段提交協議:事務管理器分兩個階段來協調資源管理器,第一階段準備資源,也就是預留事務所需的資源,若是每一個資源管理器都資源預留成功,則進行第二階段資源提交,不然協調資源管理器回滾資源。框架

2.2 TCC

TCC

TCC(Try-Confirm-Cancel) 其實是服務化的兩階段提交協議,業務開發者須要實現這三個服務接口,第一階段服務由業務代碼編排來調用 Try 接口進行資源預留,全部參與者的 Try 接口都成功了,事務管理器會提交事務,並調用每一個參與者的 Confirm 接口真正提交業務操做,不然調用每一個參與者的 Cancel 接口回滾事務。異步

2.3 Saga

Saga

Saga 是一種補償協議,在 Saga 模式下,分佈式事務內有多個參與者,每個參與者都是一個衝正補償服務,須要用戶根據業務場景實現其正向操做和逆向回滾操做。分佈式

分佈式事務執行過程當中,依次執行各參與者的正向操做,若是全部正向操做均執行成功,那麼分佈式事務提交。若是任何一個正向操做執行失敗,那麼分佈式事務會退回去執行前面各參與者的逆向回滾操做,回滾已提交的參與者,使分佈式事務回到初始狀態。

Saga 理論出自 Hector & Kenneth 1987發表的論文 Sagas。

Saga 正向服務與補償服務也須要業務開發者實現。

3、Seata 及其三種模式詳解

3.1 分佈式事務 Seata 介紹

Seata(Simple Extensible Autonomous Transaction Architecture,簡單可擴展自治事務框架)是 2019 年 1 月份螞蟻金服和阿里巴巴共同開源的分佈式事務解決方案。Seata 開源半年左右,目前已經有超過 1.1 萬 star,社區很是活躍。咱們熱忱歡迎你們參與到 Seata 社區建設中,一同將 Seata 打形成開源分佈式事務標杆產品。

Seata:github.com/seata/seata

Seata

3.2 分佈式事務 Seata 產品模塊

以下圖所示,Seata 中有三大模塊,分別是 TM、RM 和 TC。 其中 TM 和 RM 是做爲 Seata 的客戶端與業務系統集成在一塊兒,TC 做爲 Seata 的服務端獨立部署。

Seata 三大模塊

在 Seata 中,分佈式事務的執行流程:

  • TM 開啓分佈式事務(TM 向 TC 註冊全局事務記錄);
  • 按業務場景,編排數據庫、服務等事務內資源(RM 向 TC 彙報資源準備狀態);
  • TM 結束分佈式事務,事務一階段結束(TM 通知 TC 提交/回滾分佈式事務);
  • TC 彙總事務信息,決定分佈式事務是提交仍是回滾;
  • TC 通知全部 RM 提交/回滾 資源,事務二階段結束;

3.3 分佈式事務 Seata 解決方案

Seata 會有 4 種分佈式事務解決方案,分別是 AT 模式、TCC 模式、Saga 模式和 XA 模式。

Seata 的 4 種分佈式事務解決方案

3.3.1 AT 模式

今年 1 月份,Seata 開源了 AT 模式。AT 模式是一種無侵入的分佈式事務解決方案。在 AT 模式下,用戶只需關注本身的「業務 SQL」,用戶的 「業務 SQL」 做爲一階段,Seata 框架會自動生成事務的二階段提交和回滾操做。

AT 模式

AT 模式如何作到對業務的無侵入 :
  • 一階段:

在一階段,Seata 會攔截「業務 SQL」,首先解析 SQL 語義,找到「業務 SQL」要更新的業務數據,在業務數據被更新前,將其保存成「before image」,而後執行「業務 SQL」更新業務數據,在業務數據更新以後,再將其保存成「after image」,最後生成行鎖。以上操做所有在一個數據庫事務內完成,這樣保證了一階段操做的原子性。

AT 模式一階段

  • 二階段提交:

二階段若是是提交的話,由於「業務 SQL」在一階段已經提交至數據庫, 因此 Seata 框架只需將一階段保存的快照數據和行鎖刪掉,完成數據清理便可。

AT 模式二階段提交

  • 二階段回滾:

二階段若是是回滾的話,Seata 就須要回滾一階段已經執行的「業務 SQL」,還原業務數據。回滾方式即是用「before image」還原業務數據;但在還原前要首先要校驗髒寫,對比「數據庫當前業務數據」和 「after image」,若是兩份數據徹底一致就說明沒有髒寫,能夠還原業務數據,若是不一致就說明有髒寫,出現髒寫就須要轉人工處理。

AT 模式二階段回滾

AT 模式的一階段、二階段提交和回滾均由 Seata 框架自動生成,用戶只需編寫「業務 SQL」,便能輕鬆接入分佈式事務,AT 模式是一種對業務無任何侵入的分佈式事務解決方案。

3.3.2 TCC 模式

2019 年 3 月份,Seata 開源了 TCC 模式,該模式由螞蟻金服貢獻。TCC 模式須要用戶根據本身的業務場景實現 Try、Confirm 和 Cancel 三個操做;事務發起方在一階段執行 Try 方式,在二階段提交執行 Confirm 方法,二階段回滾執行 Cancel 方法。

TCC 模式

TCC 三個方法描述:

  • Try:資源的檢測和預留;
  • Confirm:執行的業務操做提交;要求 Try 成功 Confirm 必定要能成功;
  • Cancel:預留資源釋放;

螞蟻金服在 TCC 的實踐經驗

螞蟻金服在 TCC 的實踐經驗

1 TCC 設計 - 業務模型分 2 階段設計:

用戶接入 TCC ,最重要的是考慮如何將本身的業務模型拆成兩階段來實現。

以「扣錢」場景爲例,在接入 TCC 前,對 A 帳戶的扣錢,只需一條更新帳戶餘額的 SQL 便能完成;可是在接入 TCC 以後,用戶就須要考慮如何將原來一步就能完成的扣錢操做,拆成兩階段,實現成三個方法,而且保證一階段 Try  成功的話 二階段 Confirm 必定能成功。

TCC 設計 - 業務模型分 2 階段設計

如上圖所示,Try 方法做爲一階段準備方法,須要作資源的檢查和預留。在扣錢場景下,Try 要作的事情是就是檢查帳戶餘額是否充足,預留轉帳資金,預留的方式就是凍結 A 帳戶的 轉帳資金。Try 方法執行以後,帳號 A 餘額雖然仍是 100,可是其中 30 元已經被凍結了,不能被其餘事務使用。

二階段 Confirm 方法執行真正的扣錢操做。Confirm 會使用 Try 階段凍結的資金,執行帳號扣款。Confirm 方法執行以後,帳號 A 在一階段中凍結的 30 元已經被扣除,帳號 A 餘額變成 70 元 。

若是二階段是回滾的話,就須要在 Cancel 方法內釋放一階段 Try 凍結的 30 元,使帳號 A 的回到初始狀態,100 元所有可用。

用戶接入 TCC 模式,最重要的事情就是考慮如何將業務模型拆成 2 階段,實現成 TCC 的 3 個方法,而且保證 Try 成功 Confirm 必定能成功。相對於 AT 模式,TCC 模式對業務代碼有必定的侵入性,可是 TCC 模式無 AT 模式的全局行鎖,TCC 性能會比 AT 模式高不少。

2 TCC 設計 - 容許空回滾:

TCC 設計 - 容許空回滾

Cancel 接口設計時須要容許空回滾。在 Try 接口由於丟包時沒有收到,事務管理器會觸發回滾,這時會觸發 Cancel 接口,這時 Cancel 執行時發現沒有對應的事務 xid 或主鍵時,須要返回回滾成功。讓事務服務管理器認爲已回滾,不然會不斷重試,而 Cancel 又沒有對應的業務數據能夠進行回滾。

3 TCC 設計 - 防懸掛控制:

TCC 設計 - 防懸掛控制

懸掛的意思是:Cancel 比 Try 接口先執行,出現的緣由是 Try 因爲網絡擁堵而超時,事務管理器生成回滾,觸發 Cancel 接口,而最終又收到了 Try 接口調用,可是 Cancel 比 Try 先到。按照前面容許空回滾的邏輯,回滾會返回成功,事務管理器認爲事務已回滾成功,則此時的 Try 接口不該該執行,不然會產生數據不一致,因此咱們在 Cancel 空回滾返回成功以前先記錄該條事務 xid 或業務主鍵,標識這條記錄已經回滾過,Try 接口先檢查這條事務xid或業務主鍵若是已經標記爲回滾成功過,則不執行 Try 的業務操做。

4 TCC 設計 - 冪等控制:

CC 設計 - 冪等控制

冪等性的意思是:對同一個系統,使用一樣的條件,一次請求和重複的屢次請求對系統資源的影響是一致的。由於網絡抖動或擁堵可能會超時,事務管理器會對資源進行重試操做,因此極可能一個業務操做會被重複調用,爲了避免由於重複調用而屢次佔用資源,須要對服務設計時進行冪等控制,一般咱們能夠用事務 xid 或業務主鍵判重來控制。

3.3.3 Saga 模式

Saga 模式是 Seata 即將開源的長事務解決方案,將由螞蟻金服主要貢獻。在 Saga 模式下,分佈式事務內有多個參與者,每個參與者都是一個衝正補償服務,須要用戶根據業務場景實現其正向操做和逆向回滾操做。

分佈式事務執行過程當中,依次執行各參與者的正向操做,若是全部正向操做均執行成功,那麼分佈式事務提交。若是任何一個正向操做執行失敗,那麼分佈式事務會去退回去執行前面各參與者的逆向回滾操做,回滾已提交的參與者,使分佈式事務回到初始狀態。

Saga 模式

Saga 模式下分佈式事務一般是由事件驅動的,各個參與者之間是異步執行的,Saga 模式是一種長事務解決方案。

1 Saga 模式使用場景

Saga 模式使用場景

Saga 模式適用於業務流程長且須要保證事務最終一致性的業務系統,Saga 模式一階段就會提交本地事務,無鎖、長流程狀況下能夠保證性能。

事務參與者多是其它公司的服務或者是遺留系統的服務,沒法進行改造和提供 TCC 要求的接口,可使用 Saga 模式。

Saga模式的優點是:

  • 一階段提交本地數據庫事務,無鎖,高性能;
  • 參與者能夠採用事務驅動異步執行,高吞吐;
  • 補償服務即正向服務的「反向」,易於理解,易於實現;

缺點:Saga 模式因爲一階段已經提交本地數據庫事務,且沒有進行「預留」動做,因此不能保證隔離性。後續會講到對於缺少隔離性的應對措施。

2 基於狀態機引擎的 Saga 實現

基於狀態機引擎的 Saga 實現

目前 Saga 的實現通常也兩種,一種是經過事件驅動架構實現,一種是基於註解加攔截器攔截業務的正向服務實現。Seata 目前是採用事件驅動的機制來實現的,Seata 實現了一個狀態機,能夠編排服務的調用流程及正向服務的補償服務,生成一個 json 文件定義的狀態圖,狀態機引擎驅動到這個圖的運行,當發生異常的時候狀態機觸發回滾,逐個執行補償服務。固然在什麼狀況下觸發回滾用戶是能夠自定義決定的。該狀態機能夠實現服務編排的需求,它支持單項選擇、併發、異步、子狀態機調用、參數轉換、參數映射、服務執行狀態判斷、異常捕獲等功能。

3 狀態機引擎原理

狀態機引擎原理

該狀態機引擎的基本原理是,它基於事件驅動架構,每一個步驟都是異步執行的,步驟與步驟之間經過事件隊列流轉, 極大的提升系統吞吐量。每一個步驟執行時會記錄事務日誌,用於出現異常時回滾時使用,事務日誌會記錄在與業務表所在的數據庫內,提升性能。

4 狀態機引擎設計

狀態機引擎設計

該狀態機引擎分紅了三層架構的設計,最底層是「事件驅動」層,實現了 EventBus 和消費事件的線程池,是一個 Pub-Sub 的架構。第二層是「流程控制器」層,它實現了一個極簡的流程引擎框架,它驅動一個「空」的流程執行,「空」的意思是指它不關心流程節點作什麼事情,它只執行每一個節點的 process 方法,而後執行 route 方法流轉到下一個節點。這是一個通用框架,基於這兩層,開發者能夠實現任何流程引擎。最上層是「狀態機引擎」層,它實現了每種狀態節點的「行爲」及「路由」邏輯代碼,提供 API 和狀態圖倉庫,同時還有一些其它組件,好比表達式語言、邏輯計算器、流水生成器、攔截器、配置管理、事務日誌記錄等。

5 Saga 服務設計經驗

和TCC相似,Saga的正向服務與反向服務也需求遵循如下設計原則:

1)Saga 服務設計 - 容許空補償

Saga 服務設計 - 容許空補償

2)Saga 服務設計 - 防懸掛控制

Saga 服務設計 - 防懸掛控制

3)Saga 服務設計 - 冪等控制

Saga 服務設計 - 冪等控制

4)Saga 設計 - 自定義事務恢復策略

Saga 設計 - 自定義事務恢復策略

前面講到 Saga 模式不保證事務的隔離性,在極端狀況下可能出現髒寫。好比在分佈式事務未提交的狀況下,前一個服務的數據被修改了,然後面的服務發生了異常須要進行回滾,可能因爲前面服務的數據被修改後沒法進行補償操做。這時的一種處理辦法能夠是「重試」繼續往前完成這個分佈式事務。因爲整個業務流程是由狀態機編排的,即便是過後恢復也能夠繼續往前重試。因此用戶能夠根據業務特色配置該流程的事務處理策略是優先「回滾」仍是「重試」,當事務超時的時候,Server 端會根據這個策略不斷進行重試。

因爲 Saga 不保證隔離性,因此咱們在業務設計的時候須要作到「寧肯長款,不可短款」的原則,長款是指在出現差錯的時候站在我方的角度錢多了的狀況,錢少了則是短款,由於若是長款能夠給客戶退款,而短款則可能錢追不回來了,也就是說在業務設計的時候,必定是先扣客戶賬再入賬,若是由於隔離性問題形成覆蓋更新,也不會出現錢少了的狀況。

6 基於註解和攔截器的 Saga 實現

基於註解和攔截器的 Saga 實現

還有一種 Saga 的實現是基於註解+攔截器的實現,Seata 目前沒有實現,能夠看上面的僞代碼來理解一下,one 方法上定義了 @SagaCompensable 的註解,用於定義 one 方法的補償方法是 compensateOne 方法。而後在業務流程代碼 processA 方法上定義 @SagaTransactional 註解,啓動 Saga 分佈式事務,經過攔截器攔截每一個正向方法當出現異常的時候觸發回滾操做,調用正向方法的補償方法。

7 兩種 Saga 實現優劣對比

兩種 Saga 的實現各有又缺點,下面表格是一個對比:

兩種 Saga 實現優劣對比

狀態機引擎的最大優點是能夠經過事件驅動的方法異步執行提升系統吞吐,能夠實現服務編排需求,在 Saga 模式缺少隔離性的狀況下,能夠多一種「向前重試」的事情恢復策略。註解加攔截器的的最大優點是,開發簡單、學習成本低。

總結

本文先回顧了分佈式事務產生的背景及理論基礎,而後重點講解了 Seata 分佈式事務的原理以及三種模式(AT、TCC、Saga)的分佈式事務實現。

Seata 的定位是分佈式事全場景解決方案,將來還會有 XA 模式的分佈式事務實現,每種模式都有它的適用場景,AT 模式是無侵入的分佈式事務解決方案,適用於不但願對業務進行改造的場景,幾乎0學習成本。TCC 模式是高性能分佈式事務解決方案,適用於核心系統等對性能有很高要求的場景。Saga 模式是長事務解決方案,適用於業務流程長且須要保證事務最終一致性的業務系統,Saga 模式一階段就會提交本地事務,無鎖,長流程狀況下能夠保證性能,多用於渠道層、集成層業務系統。事務參與者多是其它公司的服務或者是遺留系統的服務,沒法進行改造和提供 TCC 要求的接口,也可使用 Saga 模式。

公衆號:金融級分佈式架構(Antfin_SOFA)

相關文章
相關標籤/搜索