1. 程式人生 > >螞蟻金服大規模分散式事務實踐和開源詳解 | GIAC 實錄

螞蟻金服大規模分散式事務實踐和開源詳解 | GIAC 實錄

本文整理自螞蟻金服技術專家、分散式事務 Seata 發起者之一張森(花名:紹輝)在 GIAC 全球網際網路架構大會的分享。詳細講解了在分散式架構演進中,螞蟻金服面對的跨服務、跨資料庫的業務資料一致性問題以及應對措施,並分享了分散式事務 Seata 的 AT、TCC、Saga 和 XA 四種模式。

Seata:https://gitee.com/seata/seata

GIAC-紹輝.JPG

一、自研分散式事務解決資料一致性問題

1.1 分散式事務問題產生原因

1.1.1 資料庫的水平拆分

螞蟻金服的業務資料庫起初是單庫單表,但隨著業務資料規模的快速發展,資料量越來越大,單庫單表逐漸成為瓶頸。所以我們對資料庫進行了水平拆分,將原單庫單表拆分成資料庫分片。

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

image.png

1.1.2 業務服務化拆分

在業務發展初期,“一塊大餅”的單業務系統架構,能滿足基本的業務需求。但是隨著業務的快速發展,系統的訪問量和業務複雜程度都在快速增長,單系統架構逐漸成為業務發展瓶頸,解決業務系統的高耦合、可伸縮問題的需求越來越強烈。

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

image.png

業務系統按照服務拆分之後,一個完整的業務往往需要呼叫多個服務,如何保證多個服務間的資料一致性成為一個難題。

1.2 螞蟻金服遇到的資料一致性問題

在資料庫水平拆分、服務垂直拆分之後,一個業務操作通常要跨多個數據庫、服務才能完成。在分散式網路環境下,我們無法保障所有服務、資料庫都百分百可用,一定會出現部分服務、資料庫執行成功,另一部分執行失敗的問題。

當出現部分業務操作成功、部分業務操作失敗時,業務資料就會出現不一致。以金融業務中比較常見的“轉賬”場景為例:

如下圖所示,在支付寶的“轉賬”操作中,要分別完成 4 個動作:

  1. 建立交易訂單;
  2. 建立支付訂單;
  3. A 賬戶扣錢;
  4. B 賬戶加錢;

而完成以上操作要分別訪問 3 個服務和 4 個數據庫。

圖片1.png

在分散式環境下,肯定會出現部分操作成功、部分操作失敗的問題,比如:A 賬戶的錢扣了,但是 B 賬戶的錢沒加上,這就造成了資金損失,影響資金安全。

在金融業務場景下,我們必須保證“轉賬”的原子性,要麼所有操作全部成功,要麼全部失敗,不允許出現部分成功部分失敗的現象。

為了解決跨資料庫、跨服務的業務資料一致性問題,螞蟻金服自主研發了分散式事務中介軟體。

從 2007 年開始做分散式事務並支援雙十一,至今已經有 12 年。

2013 年,螞蟻金服開始做單元化改造,分散式事務也開始支援 LDC、異地多活和高可用容災,解決了機房故障情況下服務快速恢復的問題。

2014 年,螞蟻金服分散式事務中介軟體 DTX(Distributed Transaction-eXtended)開始通過螞蟻金融雲對外輸出,我們發展了一大批的外部使用者。在發展外部客戶的過程中,外部客戶表示願意犧牲一部分效能(無螞蟻的業務規模)以換取接入便利性和無侵入性。所以在 2015 年,我們開始做無侵入的事務解決方案:FMT 模式和 XA 模式。

螞蟻金服分散式事務(Distributed Transaction-eXtended,簡稱 DTX)連結: https://tech.antfin.com/products/DTX

二、投入開源社群,共建開源分散式事務 Seata

2.1 分散式事務 Seata 介紹

Seata(Simple Extensible Autonomous Transaction Architecture,簡單可擴充套件自治事務框架)是 2019 年 1 月份螞蟻金服和阿里巴巴共同開源的分散式事務解決方案。Seata 開源半年左右,目前已經有接近一萬 star,社群非常活躍。我們熱忱歡迎大家參與到 Seata 社群建設中,一同將 Seata 打造成開源分散式事務標杆產品。

Seata:https://github.com/seata/seata image.png

2.2 分散式事務 Seata 產品模組

如下圖所示,Seata 中有三大模組,分別是 TM、RM 和 TC。 其中 TM 和 RM 是作為 Seata 的客戶端與業務系統整合在一起,TC 作為 Seata 的服務端獨立部署。

image.png

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

  • TM 開啟分散式事務(TM 向 TC 註冊全域性事務記錄);
  • 按業務場景,編排資料庫、服務等事務內資源(RM 向 TC 彙報資源準備狀態 );
  • TM 結束分散式事務,事務一階段結束(TM 通知 TC 提交/回滾分散式事務);
  • TC 彙總事務資訊,決定分散式事務是提交還是回滾;
  • TC 通知所有 RM 提交/回滾 資源,事務二階段結束。

2.3 分散式事務 Seata 解決方案

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

圖片2.png

2.3.1 AT 模式

今年 1 月份,Seata 開源了 AT 模式。AT 模式是一種無侵入的分散式事務解決方案。在 AT 模式下,使用者只需關注自己的“業務 SQL”,使用者的 “業務 SQL” 作為一階段,Seata 框架會自動生成事務的二階段提交和回滾操作。

image.png

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

在一階段,Seata 會攔截“業務 SQL”,首先解析 SQL 語義,找到“業務 SQL”要更新的業務資料,在業務資料被更新前,將其儲存成“before image”,然後執行“業務 SQL”更新業務資料,在業務資料更新之後,再將其儲存成“after image”,最後生成行鎖。以上操作全部在一個數據庫事務內完成,這樣保證了一階段操作的原子性。

圖片3.png

  • 二階段提交:

二階段如果是提交的話,因為“業務 SQL”在一階段已經提交至資料庫, 所以 Seata 框架只需將一階段儲存的快照資料和行鎖刪掉,完成資料清理即可。

圖片4.png

  • 二階段回滾:

二階段如果是回滾的話,Seata 就需要回滾一階段已經執行的“業務 SQL”,還原業務資料。回滾方式便是用“before image”還原業務資料;但在還原前要首先要校驗髒寫,對比“資料庫當前業務資料”和 “after image”,如果兩份資料完全一致就說明沒有髒寫,可以還原業務資料,如果不一致就說明有髒寫,出現髒寫就需要轉人工處理。

圖片5.png

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

2.3.2 TCC 模式

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

圖片6.png

TCC 三個方法描述:

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

業務模型分 2 階段設計:

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

以“扣錢”場景為例,在接入 TCC 前,對 A 賬戶的扣錢,只需一條更新賬戶餘額的 SQL 便能完成;但是在接入 TCC 之後,使用者就需要考慮如何將原來一步就能完成的扣錢操作,拆成兩階段,實現成三個方法,並且保證一階段 Try  成功的話 二階段 Confirm 一定能成功。

圖片7.png

如上圖所示,

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.3.3 Saga 模式

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

分散式事務執行過程中,依次執行各參與者的正向操作,如果所有正向操作均執行成功,那麼分散式事務提交。如果任何一個正向操作執行失敗,那麼分散式事務會去退回去執行前面各參與者的逆向回滾操作,回滾已提交的參與者,使分散式事務回到初始狀態。

圖片8.png

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

2.3.4 XA 模式

XA 模式是 Seata 將會開源的另一種無侵入的分散式事務解決方案,任何實現了 XA 協議的資料庫都可以作為資源參與到分散式事務中,目前主流資料庫,例如 MySql、Oracle、DB2、Oceanbase 等均支援 XA 協議。

XA 協議有一系列的指令,分別對應一階段和二階段操作。“xa start”和 “xa end”用於開啟和結束XA 事務;“xa prepare” 用於預提交 XA 事務,對應一階段準備;“xa commit”和“xa rollback”用於提交、回滾 XA 事務,對應二階段提交和回滾。

在 XA 模式下,每一個 XA 事務都是一個事務參與者。分散式事務開啟之後,首先在一階段執行“xa start”、“業務 SQL”、“xa end”和 “xa prepare” 完成 XA 事務的執行和預提交;二階段如果提交的話就執行 “xa commit”,如果是回滾則執行“xa rollback”。這樣便能保證所有 XA 事務都提交或者都回滾。

圖片9.png

XA 模式下,使用者只需關注自己的“業務 SQL”,Seata 框架會自動生成一階段、二階段操作;XA 模式的實現如下:

圖片10.png

  • 一階段:

在 XA 模式的一階段,Seata 會攔截“業務 SQL”,在“業務 SQL”之前開啟 XA 事務(“xa start”),然後執行“業務 SQL”,結束 XA 事務“xa end”,最後預提交 XA 事務(“xa prepare”),這樣便完成 “業務 SQL”的準備操作。

  • 二階段提交:

執行“xa commit”指令,提交 XA 事務,此時“業務 SQL”才算真正的提交至資料庫。

  • 二階段回滾:

執行“xa rollback”指令,回滾 XA 事務,完成“業務 SQL”回滾,釋放資料庫鎖資源。

XA 模式下,使用者只需關注“業務 SQL”,Seata 會自動生成一階段、二階段提交和二階段回滾操作。XA 模式和 AT 模式一樣是一種對業務無侵入性的解決方案;但與 AT 模式不同的是,XA 模式將快照資料和行鎖等通過 XA 指令委託給了資料庫來完成,這樣 XA 模式實現更加輕量化。

三、分散式事務在螞蟻金服的實踐

螞蟻金服從 2007 年開始研發和應用分散式事務中介軟體,用 TCC 模式解決各類金融場景的資料一致性問題,後續又演進出 FMT(AT)、XA、Saga 等模式,各種模式分別適用於各類業務場景。我們決定將螞蟻金服多年的技術積累開源出來,與社群共享螞蟻金服的科技成果。

螞蟻金服內部的分散式事務產品,在實現原理和使用方式上,與 Seata 類似,不同的是,為了支援雙十一,對效能進行了極致優化,為了支援金融系統的高可用容災,藉助螞蟻金服三地五中心架構實現了分散式事務服務的高可用容災;接下來主要介紹螞蟻金服在效能優化和高可用容災方面的實踐經驗。

圖片11.png

3.1 極致效能優化

3.1.1 同庫模式

通常,一個 TM 會產生一筆主事務日誌,一個 RM 會產生一條分支事務日誌,每個分散式事務由一個 TM 和若干 RM 組成,一個分散式事務總共會有  1+N 條事務日誌(N 為 RM 個數)。

在預設情況下,分散式事務執行過程中客戶端將事務日誌傳送給服務端,服務端再將事務日誌儲存至資料庫中,一條事務日誌的儲存鏈路會有 2 次 TCP ,分別是“客戶端到服務端”和“服務端到資料庫”, 我們稱這種模式為異庫模式。

在異庫模式下,分散式事務儲存事務日誌總共需要 2*(1+N) 次左右的 TCP 通訊。在 RM 數量較少的業務場景下,分散式事務效能還能接收,但有些業務場景下 RM 數量較多,此時事務內 TCP 數量也會增多,分散式事務效能急劇下降。

圖片12.png

在事務執行過程中,客戶端和服務端進行通訊的目的是為了儲存事務日誌。如果客戶端在儲存事務日誌時,繞過服務端直接將事務日誌寫入資料庫(如上圖“同庫模式”所示),那麼一筆事務日誌的儲存鏈路就由原來的 2 次 TCP  變成只需訪問一次資料庫便可,每條事務日誌的儲存減少了一次 TCP 通訊,整個分散式事務就減少了 N+2 次 TCP  請求,分散式事務的效能大幅提升。我們將客戶端直接將事務日誌儲存至資料庫的模式稱為同庫模式。

3.1.2 二階段非同步執行

通常情況下,分散式事務發起方會依次執行一階段和二階段方法,然後結束分散式事務,返回結果。如果讓分散式事務發起方執行完一階段之後馬上結束並返回結果,二階段交由獨立的執行緒或者程序非同步執行,這樣分散式事務的二階段會晚幾秒鐘或者若干分鐘執行,但事務的最終結果不會有任何改變。

二階段非同步執行之後,分散式事務的最終結果不會有任何影響,但是事務發起方要執行的內容減少一半(一階段和二階段都執行變成只執行一階段),直觀的使用者感受是分散式事務的效能提升了 50%。

圖片13.png

3.2 分散式事務高可用

為了保障金融系統的高可用,分散式事務服務必須達到 99.99% 的可用率。分散式事務使用了螞蟻金服的三地五中心架構部署,在每個機房都獨立部署分散式事務服務,分散式事務服務是無狀態的,而底層資料庫副本在各機房間也是雙向同步,這樣業務流量從一個機房切到另外一個機房,分散式事務服務不會對業務有任何影響,從而保證了分散式事務服務的高可用。

圖片14.png

四、總結

在分散式架構演進中,螞蟻金服對資料庫進了水平拆分,對服務面向功能進行了服務化拆分,從而出現了跨服務、跨資料庫的業務資料一致性挑戰。

 2007 年,螞蟻金服自主研發分散式事務中介軟體經歷 12 年的嚴苛業務錘鍊。2019 年,將多年的技術積累分享給開源分散式事務 Seata,並持續投入社群共建。目前 Seata 提供了 AT、TCC、Saga 和 XA 四種模式,每一種模式分別有各自的應用場景,豐富的解決方案幫助使用者解決給了各類場景的資料一致性問題。

最後一部分,分享了螞蟻金服具體的實踐。為了支援雙十一的高效能需求,對分散式事務進行了極致的效能優化,例如同庫模式、二階段非同步執行。為了使金融服務的可用性達到 99.99%,螞蟻金服分散式事務採用三地五中心架構,異地多活的部署模式保障了分散式事務服務的高可用。

相關連結: