天天看點

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

,有趣實用的分布式架構頻道。

本文根據 SOFAChannel#12 直播分享整理,主題:螞蟻金服分布式事務實踐解析。

回顧視訊以及 PPT 檢視位址見文末。歡迎加入直播互動釘釘群 : 30315793,不錯過每場直播。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

大家好,我是今天分享的講師仁空,目前是螞蟻金服分布式事務産品的研發。今天跟大家分享的是螞蟻金服分布式事務實踐解析,也就是分布式事務 Seata 在螞蟻金服内部的實踐。

今天我們将從以下 4 個主題進行詳細介紹:

  • 為什麼會有分布式事務産品的需求;
  • 理論界針對這個需求提出的一些理論和解決方案;
  • 螞蟻金服在工程上是如何解決這個問題的;
  • 針對螞蟻金服業務場景的性能優化;

分布式事務産生背景

首先是分布式事務産生的背景。

支付寶支付産品在 2003 年上線的時候,那時候的軟體形态是單體應用,在一個應用内完成所有的業務邏輯操作。随着軟體的工業化,場景越來越複雜,軟體也越做越大,所有的業務在一個應用内去完成變的不可能,出現了軟體子產品化、服務化。

在從單體應用更新到分布式架構過程中,很自然得需要進行業務服務拆分,将原來糅在一個系統中的業務進行梳理,拆分出能獨立成體系的各個子系統,例如交易系統、支付系統、賬務系統等,這個過程就是服務化。業務服務拆分之後,原來一個服務就能完成的業務操作現在需要跨多個服務進行了。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

另一個就是資料庫拆分,分庫分表。原來的單體資料庫存不下的這麼多資訊,按服務次元拆庫,比如把使用者相關的存一起,形成使用者庫,訂單放一塊形成訂單庫,這個是拆庫的過程;另一個是拆表,使用者資訊按照使用者 ID 散列到不同的 DB 中,水準拆分,資料庫的容量增大了。這樣分庫分表之後,寫操作就會跨多個資料庫了。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

分布式事務理論基礎

我們可以看到,在分布式架構中,跨資料庫、跨服務的問題是天然存在的。一個業務操作的完成,需要經過多個服務配合完成,這些服務操作的資料可能在一個機房中,也可能跨機房存在,如果中間某一個服務因為網絡或機房硬體的問題發生了抖動,怎麼保證這筆業務最終的狀态是正确的,比如支付場景,怎麼防止我轉錢給你的過程中,我的錢扣了,而對方的賬戶并沒有收到錢。這個就是業務最終一緻性的問題,是分布式事務需要解決的問題。

2PC 協定

針對這個問題,理論界也提出了解決方案,其中最為人熟知的就是二階段協定了,簡稱2PC(Two Phase Commitment Protocol)兩階段送出協定。

兩階段送出協定,就是把整個過程分成了兩個階段,這其中,它把參與整個過程的實體分成了兩類角色,一個叫事務管理器或事務協調者,一個叫資料總管,事務管理器我們也把它叫做事務發起方,資料總管稱為事務參與者。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

兩個階段,第一個階段是資源準備階段,比如我要轉賬,我要先查詢下我的餘額夠不夠,夠的話我就把餘額資源預留起來,然後告訴發起方“我準備好了”,第二個階段,事務發起方根據各個參與者的回報,決定事務的二階段操作是送出還是取消。

TCC 協定

另一個協定是 TCC 協定,各個參與者需要實作3個操作:Try、Confirm 和 Cancel,3個操作對應2個階段,Try 方法是一階段的資源檢測和預留階段,Confirm 和 Cancel 對應二階段的送出和復原。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

圖中,事務開啟的時候,由發起方去觸發一階段的方法,然後根據各個參與者的傳回狀态,決定二階段是調 Confirm 還是 Cancel 方法。

螞蟻金服分布式事務介紹

2019年,螞蟻金服跟阿裡巴巴共同開源了分布式事務 Seata ,目前 Seata 已經有 TCC、AT、Saga 模式,Seata 意為:Simple Extensible Autonomous Transaction Architecture,是一套一站式分布式事務解決方案。今天的分享也是 Seata 在螞蟻金服内部的實踐。

分布式事務在螞蟻金服的發展

基于上述的理論,接下來我們詳細看下螞蟻金服的分布式事務實作。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

經過多年的發展,螞蟻金服内部針對不同的場景發展了幾種不同的模式,最早的是 TCC 模式,也就是上面講的 Try - confirm - Cancel,我們定義接口規範,業務自己實作這3個操作。這個模式提供了更多的靈活性,因為是業務自己實作的,使用者可以介入兩階段送出過程,以達到特殊場景下的自定義優化及特殊功能的實作,這個模式能幾乎滿足任何我們想到的事務場景,比如自定義補償型事務、自定義資源預留型事務、消息事務等場景。TCC 模式廣泛用于螞蟻金服内部各金融核心系統。

這裡要強調一點的是,TCC 模式與底層資料庫事務實作無關,是一個抽象的基于 Service 層的概念,也就是說,在 TCC 的範圍内,無論是關系型資料庫 MySQL,Oracle,還是 KV 存儲 MemCache,或者列式存儲資料庫 HBase,隻要将對它們的操作包裝成 TCC 的參與者,就可以接入到 TCC 事務範圍内。

TCC 模式的好處是靈活性,弊端是犧牲了易用性,接入難度比較大,所有參與者需要進行改造提供 Try - Confirm - Cancel 三個方法。為了解決 TCC 模式的易用性問題,螞蟻金服分布式事務推出了架構管理事務模式(Framework - Managed Transactions,簡稱 FMT),也就是 Seata 中的 AT 模式。FMT 模式解決分布式事務的易用性問題,最大的特點是易于使用、快速接入、對業務代碼無侵入。

XA 模式是依賴于底層資料庫實作的。

Saga 模式是基于沖正模型實作的一個事務模式,現在的銀行業金融機構普遍用的是沖正模型。

這期我們重點講 TCC 和 FMT,關于 Saga 模式,之前 Saga 模式也有專場直播分享過,感興趣的可以看一下之前的直播回顧:《

Seata 長事務解決方案 Saga 模式 | SOFAChannel#10 回顧

》。

TCC 模式在螞蟻金服内的使用

首先看下 TCC 模式,主要包含一下幾個子產品:

  • 參與者,它要實作全部的三個方法,Try、Confirm 和 Cancel;
  • 發起方,主要是作為協調者的角色,編排各個參與者,比如調用參與者的一階段方法,決策二階段是執行送出還是復原;
螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

舉個例子,比如在這個流程圖中,存在一個發起方和兩個參與者,兩個參與者分别實作了 Try、Confirm 和 Cancel 接口,第一階段被包含在發起方的本地事務模版中(圖中黃顔色的兩條虛線就是發起方本地事務的範圍),也就是說發起方負責調用各個參與者的一階段方法,發起方的本地事務結束後,開始執行二階段操作,二階段結束則整個分布式事務結束。

二階段是通過 Spring 提供的事務同步器實作的,發起方在發起一個分布式事務的時候,會注冊一個事務同步器,當發起方本地事務結束的時候,會進入事務同步器的回調方法中。如果發起方的本地事務失敗,則在回調中自動復原所有參與者。如果發起方的本地事務成功,則二階段自動送出所有參與者。二階段結束後,删除所有事務記錄。

總結一下:

  1. 事務發起方是分布式事務的協調者;
  2. 分布式事務必須在本地事務模闆中進行,發起方本地事務的最終狀态(送出或復原)決定整個分布式事務的最終狀态;
  3. 發起方主職責:開啟一個分布式事務 + 調用參與者一階段方法。發起方實作的時候,首先是開啟一個本地事務,調用 Start 開啟分布式事務,架構會自動注冊一個 Spring 事務同步器,然後發起方發起對參與者 Try 方法的調用,當有一個 Try 方法失敗,則阻斷發起方本地事務,狀态置為復原;否則,所有的參與者 Try 成功,整個分布式事務的狀态就是送出。架構會利用事務同步器自動去執行參與者的二階段方法;
  4. 使用資料庫持久化記錄事務資料,也就是會跟蹤發起方和各個參與者的狀态,我們稱為主事務狀态和分支事務狀态。這樣我們就知道一個大事務整體是處于什麼狀态,每個參與者又是什麼狀态,當一筆事務失敗時,我們就能撈起那些失敗的參與者,進行補償重試;

上面講了整個流程以及發起方的實作内容,現在看下業務在實作參與者的時候,需要遵循以下規範:

  • 業務模型分二階段設計;
  • 幂等控制;
  • 并發控制;
  • 允許空復原;
  • 防懸挂控制;

我們逐個了解一下:

  • 二階段設計

二階段設計和幂等控制比較容易明白。二階段設計就是一階段的資源預留和二階段的送出復原。

比如以扣錢場景為例,賬戶 A 有 100 元,要扣除其中的 30 元。一階段要先檢查資源是否足夠,賬戶餘額是否大于等于 30 塊,資源不足則需要立馬傳回失敗;資源足夠則把這部分資源預留起來,預留就是鎖資源,鎖的粒度可大可小,盡量是按照最小粒度、盡快釋放的原則來,比如這裡引入一個“當機部分”的字段,“可用餘額”在一階段後就能立馬得到釋放,鎖的是當機字段。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

二階段,如果是送出則真正扣除當機的 30 元;如果是復原的話,則把當機部分加回可用餘額裡。

我們看個具體的客戶案例,網商銀行在使用 TCC 時,劃分了三層,最上一層是具體的業務平台,承接着外部不斷變化的業務需求;中間是資産交換服務,是事務發起方層,由它來發起和編排各種不同的事務鍊路;最底下一層是事務參與者層,提供最基礎的服務,比如存款核心提供的存入、支出、當機、解凍服務,借記賬務的各種原子服務等。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

看下我們日常生活中常見的幾個金融業務場景,支出、存入、當機、解凍、提現、手續費和銷戶。提現場景,比如信用卡提現至銀行卡,類似 A 到 B 的轉賬;手續費,跟轉賬類似。

下面重點介紹一下其他 4 個場景:支出(扣款)、存入(記入)、當機和解凍四個 Case。

首先,看下賬戶表的設計,前面說過,在設計的時候,需要盡可能減少鎖的時間和鎖的粒度,這裡賬戶表有這4個字段:目前餘額、未達金額、業務當機金額和預當機金額。使用者看到的餘額 = 目前金額 - 預當機 - 業務當機金額。

支出(扣款)場景

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

先來看下支出(扣款)場景下,賬戶表裡各字段的數額變化。初始狀态下,顯示的賬戶餘額,和目前餘額是一緻的。TCC 的一階段檢查并預留資源,這裡對應的資源是

“預當機金額”字段,預當機金額設定為 100 元,目前餘額不變。因為 100 塊被預當機了,顯示給使用者的可用餘額現在是 900 元。如果二階段是送出的話,就釋放預當機金額,扣除目前餘額,賬戶的目前餘額就是 900 元。如果二階段不是送出,是復原,這裡就是把一階段的資源釋放,也就是把預當機金額釋放回去,顯式的賬戶餘額重新變成 1000 元。

存入場景

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

上面是支出(扣款)場景,再來看下存入的場景。初始狀态還是目前餘額和顯式的可用餘額都是1000元。因為是存入,一階段的話就是“未達金額”加 100 元,顯示的可用餘額還是不變。二階段如果是送出,就把未達金額清除,把這部分的錢加到目前餘額,目前餘額就是 1100 元了。如果二階段是復原,直接清除一階段的未達金額即可。

當機場景

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

當機場景則是在一階段是資源預留,就是預當機,預當機金額字段設定為 100 元,顯示給使用者的可用餘額也要少 100 塊。二階段如果是送出,就是真正當機,把預當機金額釋放,添加業務當機金額。二階段復原的話,就是把一階段的預當機釋放。

解凍場景

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

最後看下解凍場景,一階段檢查賬戶狀态是不是可用,二階段如果送出,就釋放當機金額,顯示的可用餘額就多了 100 元。二階段如果是復原狀态,就什麼都不用做。

以上分享了接入 TCC 如何進行二階段設計以及如何進行資源預留,用實際的金融場景分析了下 TCC 一二階段需要做的事情。因為二階段設計是 TCC 接入的關鍵,是以進行了重點闡述。接下來我們繼續看 TCC 設計的其他規範。

  • 幂等控制

幂等控制,就是 Try-Confirm-Cancel 三個方法均需要保持幂等性。無論是網絡資料包重傳,還是異常事務的補償執行,都會導緻 TCC 服務的 Try、Confirm 或者 Cancel 操作被重複執行;使用者在實作 TCC 服務時,需要考慮幂等控制,即 Try、Confirm、Cancel 執行一次和執行多次的業務結果是一樣的。

  • 并發控制

并發控制即當兩個并發執行的分布式事務操作同一個賬号時,當機的部分是互相隔離的,也就是 T1 當機金額隻能被事務 1 使用,T2 當機金額隻能被事務 2 使用。當機資源與事務 ID 之間建立關聯關系。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理
  • 允許空復原

首先對空復原的定義就是 Try 未執行,Cancel 先執行了。正常是一階段的請求先執行,然後才是二階段的請求。出現空復原的原因,是網絡丢包導緻的,調用 Try 方法時 RPC timeout 了,分布式事務復原,觸發 Cancel 調用;參與者未收到 Try 請求而收到了 Cancel 請求,出現空復原。

我們在設計參與者時,要支援這種空復原。

  • 防懸挂

懸挂的定義是 Cancel 比 Try 先執行。不同于空復原,空復原是 Try 方法的請求沒有收到。懸挂是 Try 請求到達了,隻不過由于網絡擁堵,Try 的請求晚于二階段的 Cancel 方法。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

整個流程是這樣的:

  • 調用 TCC 服務 Try 方法,網絡擁堵(未丢包),RPC逾時;
  • 分布式事務復原;
  • TCC 服務 Cancel 被調用,執行了空復原;整個分布式事務結束;
  • 被擁堵的 Try 請求到達 TCC 服務,并被執行;出現了二階段 Cancel 請求比一階段 Try 請求先執行的情況,TCC 參與者懸挂;

解決懸挂的問題,可以跟蹤事務的執行,如果已經復原過了,一階段不應該正常執行,這時候要拒絕 Try 的執行。

FMT 模式在螞蟻金服内的使用

接下來我們來看一下 FMT(Framework-Managerment-Transaction)架構管理事務模式。

之前介紹幾個事務模式的時候,說過 TCC 模式雖然靈活,功能強大,能做很多定制和優化,但是使用難度上比較大,業務系統要進行二階段改造,編碼工作非常多。

針對那些對性能要求并不高,業務體量并不大的中小業務,我們推出了 FMT 模式——架構管理事務,從名字上看,就是大部分工作由架構自動完成,業務隻需要關注實作自己的業務 SQL 即可。

FMT 還是基于二階段的模型,業務隻需要關注一階段實作自己的業務 SQL,二階段的自動送出復原由架構來完成。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

架構托管的二階段,需要基于對一階段的分析。在一階段中,會執行下面幾個步驟:對 SQL 進行解析,提取表的中繼資料,儲存 SQL 執行前的值,執行 SQL,儲存執行後的快照,儲存行鎖。

下面看下每個階段具體做的事:

查詢操作不涉及事務,我們這裡以一個更新操作為例,首先要對操作的 SQL 進行文法語義分析,提取出關于這條記錄的全部資訊,包括是屬于哪張表、查詢條件是什麼、有哪些字段、這些記錄的主鍵等,這些資訊可以通過 JDBC MetaData api 就能拿到。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

然後我們開始儲存執行前的快照資料,把目标記錄的所有字段的目前值存到 undo log 裡,存完後真正執行 SQL,SQL 執行後原來的一些字段值就已經産生變化了,我們把新的快照資料存到 redo log 裡。最後把表名稱和記錄主鍵值存到行鎖表,代表目前這個事務正在操作的是哪些記錄。

有了這些資訊後,架構就完全能自己去執行二階段操作了。比如,當事務需要進行二階段送出,因為在一階段裡業務SQL 已經執行了,二階段隻需要把産生的中間資料删掉即可。當二階段復原時,因為我們儲存了 SQL 執行的快照資料,是以還原回執行前的快照資料即可,同時把中間資料删掉。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

這裡我們知道了 undo 和 redo log 的作用,接下來講講行鎖。行鎖是用來進行并發控制的。當一個事務在操作一條記錄前,會先去行鎖表裡查下有沒有這條記錄的鎖資訊,如果有,說明目前已經有一個事務搶占了,需要等待那個事務把鎖釋放。圖中,事務 1 在一階段對記錄上鎖,這個時候事務 2 進來,隻能等待,等事務 1 二階段送出,把鎖釋放,事務 2 這時候才能加鎖成功。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

極緻性能優化

最後,我們看看在螞蟻金服内部,針對雙十一、雙十二這種大促,為了達到更好的性能狀态,做的一些優化。

二階段異步化

一個是二階段異步化,因為一階段的結果已經能決定整個事務的狀态了,而且資源也都預留好了,剩下的二階段可以等請求峰值過後再去執行。這樣,分布式事務耗時由執行 try + confirm 或者 try + cancel 縮減成 try,提高了吞吐量。雖然結果有延遲的,但最終結果無任何影響。

異步的二階段方法,在請求洪峰過後,會由事務恢複服務撈起執行。

螞蟻金服分布式事務實踐解析 | SOFAChannel#12 直播整理

同庫模式

另一個優化,在事務記錄上。分布式事務在推進過程中,會記錄事務日志,如果這個事務日志是放到 Server 這邊的,發起方更新事務狀态時,需要跨 RPC 調用到Server方那邊,影響分布式事務的性能。如果将事務日志存在業務資料庫,則每次記錄狀态的就是業務本地執行的,減少 RPC 調用次數,進而提升了性能。

總結

以上就是本期分享的全部内容,我們先從事務産生的背景入手,在現在分布式架構的體系結構下,跨服務協同調用是常态,而網絡、資料庫、機器等都具有不可靠性,如果保證這中間操作要麼全部成功,要麼全部失敗,是大家面臨的共同問題,特别是金融場景下,對解決這個問題更有迫切性,螞蟻金服作為一家金融科技公司,在這方面也進行了探索,積累了很多經驗。

在介紹螞蟻金服的分布式事務中間件之前,先介紹了一些分布式事務的理論背景,包括兩階段協定和 TCC 協定。基于理論背景,重點介紹了螞蟻金服在分布式事務上的 TCC、FMT 模式的應用,分享了實作原理和設計規範以及 TCC 二階段設計等。最後介紹了針對雙十一雙十二這種大促活動,如何進行二階段異步化和同庫模式的優化,來支撐零點峰值時的洪峰請求。

以上就是本期分享的全部内容,如果大家對螞蟻金服在分布式事務中的實踐以及 Seata 有問題跟興趣,也可以在群内與我們交流。

本期視訊回顧以及 PPT 檢視位址

https://tech.antfin.com/community/live/1119