螞蟻金服大規模分布式事務實踐和開源歷程

運營增長 發佈 2020-04-21T07:18:23+00:00

一、自研分布式事務解決數據一致性問題1.1分布式事務問題產生原因1.1.1 資料庫的水平拆分螞蟻金服的業務資料庫起初是單庫單表,但隨著業務數據規模的快速發展,數據量越來越大,單庫單表逐漸成為瓶頸。

一、自研分布式事務解決數據一致性問題

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

1.1.1 資料庫的水平拆分

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

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

1.1.2 業務服務化拆分

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

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

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

1.2 螞蟻金服遇到的數據一致性問題

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

當出現部分業務操作成功、部分業務操作失敗時,業務數據就會出現不一致。以金融業務中比較常見的「轉帳」場景為例:

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

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

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

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

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

為了解決跨資料庫、跨服務的業務數據一致性問題,螞蟻金服自主研發了分布式事務中間件。

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

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

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

二、投入開源社區,共建開源分布式事務 Seata

2.1 分布式事務 Seata 介紹

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

2.2 分布式事務 Seata 產品模塊

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

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

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

2.3 分布式事務 Seata 解決方案

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

2.3.1 AT 模式

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

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

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

  • 二階段提交:

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

  • 二階段回滾:

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

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

2.3.2 TCC 模式

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

TCC 三個方法描述:

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

業務模型分 2 階段設計:

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

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

如上圖所示,

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 模式下,分布式事務內有多個參與者,每一個參與者都是一個沖正補償服務,需要用戶根據業務場景實現其正向操作和逆向回滾操作。

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

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 事務都提交或者都回滾。

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

  • 一階段:

在 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 類似,不同的是,為了支持雙十一,對性能進行了極致優化,為了支持金融系統的高可用容災,藉助螞蟻金服三地五中心架構實現了分布式事務服務的高可用容災;接下來主要介紹螞蟻金服在性能優化和高可用容災方面的實踐經驗。

3.1 極致性能優化

3.1.1 同庫模式

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

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

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

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

3.1.2 二階段異步執行

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

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

3.2 分布式事務高可用

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

四、總結

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

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

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

作者:張森(花名:紹輝)螞蟻金服技術專家、分布式事務 Seata 發起者之一。

關鍵字: