分散式事務解決方案與適用場景分析

原創聲明:本文系作者原創,謝絕個人、媒體、公眾號或網站未經授權轉載,違者追究其法律責任。

基於 XA 協議的應用場景

XA 協議在架構上與 TCC 模型相比,最大的不同是 XA 直接作用於資源層,而後者作用於服務層。

資源層更普適,並且對業務幾乎沒有侵入,但是為了適應各種業務場景使用,需要嚴格遵循事務 ACID 特性;服務層更接近業務,可以針對不同業務做特定的優化處理,追求更高的極限性能。

當然,並不是說 XA 協議只能作用於單個服務內部的多資源場景,跨服務的多資源場景也是可以的,只不過同樣需要額外的事務傳遞機制。

在《分散式事務綜述》一中介紹過,XA 協議通過每個 RM(Resource Manager,資源管理器)的本地事務隔離性來保證全局隔離,並且需要通過串列化隔離級別來保證分散式事務一致性。但是,串列化隔離級別存在一定的性能問題,如下所示:

在串列化隔離級別下,會為本來不加鎖的 Select 快照讀操作都加上讀鎖,導致鎖持有時間增加,並發性能進一步降低。當實現了無鎖的全局一致性讀取以後,比如分散式 MVCC,可以大幅減少鎖持有時間,並發性能會獲得較大提升。

但是不管怎麼優化實現,分散式事務的熱點數據並發性能最高就是趨近於單機本地事務。所以,無論是基於 XA 協議實現的分散式事務,還是單機本地事務,都是存在熱點數據並發性能極限的。

那麼 XA 協議最大的作用是什麼呢?其最大的作用在於資料庫資源橫向擴展時,能保證多資源訪問的事務屬性。

當單台 RM 機器達到資源性能瓶頸,無法滿足業務增長需求時,就需要橫向擴展 RM 資源,形成 RM 集群。通過橫向擴展資源,提升非熱點數據的並發性能,這對於大體量的互聯網產品來說,是至關重要的。

以上圖為例,假設單台 RM 的非熱點數據並發性能為 100 TPS,那麼 5台 RM 就是 500 TPS,就算一個分散式事務平均涉及 2 台 RM,也有 250 TPS,提升了 2.5 倍的非熱點並發能力。

綜上所述,基於 XA 協議實現的分散式事務並不能提升熱點並發性能,其意義在於橫向擴展資源提升非熱點數據並發性能時,能嚴格保證對多資源訪問的事務 ACID 特性。

至於熱點數據並發性能問題,對於一般的應用來說,經過 SQL 層面一定的性能優化之後,其並發性能基本就能夠滿足業務的需求。如果經過優化,達到性能極限之後,還不能滿足,就需要上升到業務層面,根據業務特點,通過專門的業務邏輯或業務架構優化來實現。

直接在資源層實現分散式事務的另外一點好處是其普適性,可以對上層業務屏蔽底層實現細節。這一點在雲服務時代特別有用,雲服務面對的是大量的中小企業,甚至是個人開發者,業務訴求不盡相同,普適、標準的分散式事務產品是非常有必要的,可以讓開發者從底層技術細節中脫離出來,更專註於業務邏輯的實現,從而獲得更高效、快速的業務發展。

基於 TCC 模型的應用場景

TCC 分散式事務模型直接作用於服務層。不與具體的服務框架耦合,與底層 RPC 協議無關,與底層存儲介質無關,可以靈活選擇業務資源的鎖定粒度,減少資源鎖持有時間,可擴展性好,可以說是為獨立部署的 SOA 服務而設計的。

TCC 模型優勢

對於 TCC 分散式事務模型,筆者認為其在業務場景應用上,有兩方面的意義。

1、跨服務的分散式事務

這一部分的作用與 XA 類似,服務的拆分,也可以認為是資源的橫向擴展,只不過方向不同而已。

橫向擴展可能沿著兩個方向發展:

1. 功能擴展。根據功能對數據進行分組,並將不同的功能組分布在多個不同的資料庫上,這實際上就是 SOA 架構下的服務化。

2. 數據分片,在功能組內部將數據拆分到多個資料庫上,為橫向擴展增加一個新的維度。

下圖簡要闡釋了橫向數據擴展策略:

橫向擴展的兩種方法可以同時進行運用:用戶信息(Users)、產品信息(Products)與交易信息(Trans)三個不同功能組可以存儲在不同的資料庫中。另外,每個功能組內根據其業務量可以再拆分到多個資料庫中,各功能組可以相互獨立地進行擴展。

因此,TCC 的其中一個作用就是在按照功能橫向擴展資源時,保證多資源訪問的事務屬性。

2、兩階段拆分

TCC 另一個作用就是把兩階段拆分成了兩個獨立的階段,通過資源業務鎖定的方式進行關聯。資源業務鎖定方式的好處在於,既不會阻塞其他事務在第一階段對於相同資源的繼續使用,也不會影響本事務第二階段的正確執行。

XA模型的並發事務

TCC 模型的並發事務

可以發現 TCC 模型進一步減少了資源鎖的持有時間。同時,從理論上來說,只要業務允許,事務的第二階段什麼時候執行都可以,反正資源已經業務鎖定,不會有其他事務動用該事務鎖定的資源。

這對業務有什麼好處呢?拿支付寶的擔保交易場景來說,簡化情況下,只需要涉及兩個服務,交易服務和賬務服務。交易作為主業務服務,賬務作為從業務服務,提供 Try、Commit、Cancel 介面:

1. Try 介面扣除用戶可用資金,轉移到預凍結資金。預凍結資金就是業務鎖定方案,每個事務第二階段只能使用本事務的預凍結資金,在第一階段執行結束後,其他並發事務也可以繼續處理用戶的可用資金。

2. Commit 介面扣除預凍結資金,增加中間賬戶可用資金(擔保交易不能立即把錢打給商戶,需要有一個中間賬戶來暫存)。

假設只有一個中間賬戶的情況下,每次調用支付服務的 Commit 介面,都會鎖定中間賬戶,中間賬戶存在熱點性能問題。

但是,在擔保交易場景中,七天以後才需要將資金從中間賬戶劃撥給商戶,中間賬戶並不需要對外展示。因此,在執行完支付服務的第一階段後,就可以認為本次交易的支付環節已經完成,並向用戶和商戶返回支付成功的結果,並不需要馬上執行支付服務二階段的 Commit 介面,等到低鋒期時,再慢慢消化,非同步地執行。

可能部分讀者認為擔保交易比較特殊,其實直付交易(直接把錢打到商戶賬戶的交易模式,Commit 介面扣除預凍結資金以後,不是轉移到中間賬務,而是直接轉移到商戶賬戶)也可以這樣使用,只要提前告知商戶,高峰期交易資金不是實時到賬,但保證在一定時間之內結算完成,商戶應該也是可以理解的。

這就是 TCC 分散式事務模型的二階段非同步化功能,從業務服務的第一階段執行成功,主業務服務就可以提交完成,然後再由框架非同步的執行各從業務服務的第二階段。

通用型 TCC 解決方案

通用型 TCC 解決方案就是最典型的 TCC 分散式事務模型實現,所有從業務服務都需要參與到主業務服務的決策當中。

適用場景

由於從業務服務是同步調用,其結果會影響到主業務服務的決策,因此通用型 TCC 分散式事務解決方案適用於執行時間確定且較短的業務,比如互聯網金融企業最核心的三個服務:交易、支付、賬務:

當用戶發起一筆交易時,首先訪問交易服務,創建交易訂單;然後交易服務調用支付服務為該交易創建支付訂單,執行收款動作,最後支付服務調用賬務服務記錄賬戶流水和記賬。

為了保證三個服務一起完成一筆交易,要麼同時成功,要麼同時失敗,可以使用通用型 TCC 解決方案,將這三個服務放在一個分散式事務中,交易作為主業務服務,支付作為從業務服務,賬務作為支付服務的嵌套從業務服務,由 TCC 模型保證事務的原子性。

支付服務的 Try 介面創建支付訂單,開啟嵌套分散式事務,並調用賬務服務的 Try 介面;賬務服務在 Try 介面中凍結買家資金。一階段調用完成後,交易完成,提交本地事務,由 TCC 框架完成分散式事務各從業務服務二階段的調用。

支付服務二階段先調用賬務服務的 Confirm 介面,解凍買家資金;增加賣家可用資金。調用成功後,支付服務修改支付訂單為完成狀態,完成支付。

當支付和賬務服務二階段都調用完成後,整個分散式事務結束。

非同步確保型 TCC 解決方案

非同步確保型 TCC 解決方案的直接從業務服務是可靠消息服務,而真正的從業務服務則通過消息服務解耦,作為消息服務的消費端,非同步地執行。

可靠消息服務需要提供 Try,Confirm,Cancel 三個介面。Try 介面預發送,只負責持久化存儲消息數據;Confirm 介面確認發送,這時才開始真正的投遞消息;Cancel 介面取消發送,刪除消息數據。

消息服務的消息數據獨立存儲,獨立伸縮,降低從業務服務與消息系統間的耦合,在消息服務可靠的前提下,實現分散式事務的最終一致性。

此解決方案雖然增加了消息服務的維護成本,但由於消息服務代替從業務服務實現了 TCC 介面,從業務服務不需要任何改造,接入成本非常低。

適用場景

由於從業務服務消費消息是一個非同步的過程,執行時間不確定,可能會導致不一致時間窗口增加。因此,非同步確保性 TCC 分散式事務解決方案只適用於對最終一致性時間敏感度較低的一些被動型業務(從業務服務的處理結果不影響主業務服務的決策,只被動的接收主業務服務的決策結果)。比如會員註冊服務和郵件發送服務:

當用戶註冊會員成功,需要給用戶發送一封郵件,告訴用戶註冊成功,並提示用戶激活該會員。但要注意兩點:

1. 如果用戶註冊成功,一定要給用戶發送一封郵件;

2. 如果用戶註冊失敗,一定不能給用戶發送郵件。

因此,這同樣需要會員服務和郵件服務保證原子性,要麼都執行,要麼都不執行。不一樣的是,郵件服務只是一種被動型的業務,並不影響用戶是否能夠註冊成功,它只需要在用戶註冊成功以後發送郵件給用戶即可,郵件服務不需要參與到會員服務的活動決策中。

對於此種業務場景,可以使用非同步確保型TCC分散式事務解決方案,如下:

由可靠消息服務來解耦會員和郵件服務,會員服務與消息服務組成 TCC 事務模型,保證事務原子性。然後通過消息服務的可靠特性,確保消息一定能夠被郵件服務消費,從而使得會員與郵件服務在同一個分散式事務中。同時,郵件服務也不會影響會員服務的執行過程,只在會員服務執行成功後被動接收發送郵件的請求。

補償型 TCC 解決方案

補償型 TCC 解決方案與通用型 TCC 解決方案的結構相似,其從業務服務也需要參與到主業務服務的活動決策當中。但不一樣的是,前者的從業務服務只需要提供 Do 和 Compensate 兩個介面,而後者需要提供三個介面。

Do 介面直接執行真正的完整業務邏輯,完成業務處理,業務執行結果外部可見;Compensate 操作用於業務補償,抵消或部分抵消正向業務操作的業務結果,Compensate操作需滿足冪等性。

與通用型解決方案相比,補償型解決方案的從業務服務不需要改造原有業務邏輯,只需要額外增加一個補償回滾邏輯即可,業務改造量較小。但要注意的是,業務在一階段就執行完整個業務邏輯,無法做到有效的事務隔離,當需要回滾時,可能存在補償失敗的情況,還需要額外的異常處理機制,比如人工介入。

適用場景

由於存在回滾補償失敗的情況,補償型 TCC 分散式事務解決方案只適用於一些並發衝突較少或者需要與外部交互的業務,這些外部業務不屬於被動型業務,其執行結果會影響主業務服務的決策,比如機票代理商的機票預訂服務:

該機票服務提供多程機票預訂服務,可以同時預訂多趟行程航班機票,比如從北京到聖彼得堡,需要第一程從北京到莫斯科,以及第二程從莫斯科到聖彼得堡。

當用戶預訂機票時,肯定希望能同時預訂這兩趟航班的機票,只預訂一趟航班對用戶來說沒有意義。因此,對於這樣的業務服務同樣提出了原子性要求,如果其中一趟航班的機票預訂失敗,另外一趟需要能夠取消預訂。

但是,由於航空公司相對於機票代理商來說屬於外部業務,只提供訂票介面和取消預訂介面,想要推動航空公司改造是極其困難的。因此,對於此類業務服務,可以使用補償型 TCC 分散式事務解決方案,如下:

網關服務在原有邏輯基礎上增加 Compensate 介面,負責調用對應航空公司的取消預訂介面。

在用戶發起機票預訂請求時,機票服務先通過網關 Do 介面,調用各航空公司的預訂介面,如果所有航班都預訂成功,則整個分散式事務直接執行成功;一旦某趟航班機票預訂失敗,則分散式事務回滾,由 TCC 事務框架調用各網關的 Compensate 補償介面,其再調用對應航空公司的取消預訂介面。通過這種方式,也可以保證多程機票預訂服務的原子性。

總 結

對於現在的互聯網應用來說,資源橫向擴展提供了更多的靈活性,是一種比較容易實現的向外擴展方案,但是同時也明顯增加了複雜度,引入一些新的挑戰,比如資源之間的數據一致性問題。

橫向數據擴展既可以按數據分片擴展,也可以按功能擴展。XA 與 TCC 模型在這一點上的作用類似,都能在橫向擴展資源的同時,保證多資源訪問的事務屬性,只不過前者作用於數據分片時,後者作用於功能擴展時。

XA 模型另外一個意義在於其普適性,拋開性能問題的情況下,幾乎可以適用於所有業務模式,這對於一些基礎性的技術產品來說是非常有用的,比如分散式資料庫、雲服務的分散式事務框架等。

TCC 模型除了跨服務的分散式事務這一層作用之外,還具有兩階段劃分的功能,通過業務資源鎖定,允許第二階段的非同步執行,而非同步化思想正是解決熱點數據並發性能問題的利器之一。

本文結合具體的業務場景和例子,對比分析了各分散式事務解決方案在性能、熱點衝突、接入複雜度和適用場景等方面的能力,希望能幫助各位讀者對分散式事務有更深一層的理解。

業務各有各的不同,有些業務能容忍短期不一致,有些業務的操作可以冪等,無論什麼樣的分散式事務解決方案都有其優缺點,沒有一個銀彈能夠適配所有。因此,業務需要什麼樣的解決方案,還需要結合自身的業務需求、業務特點、技術架構以及各解決方案的特性,綜合分析,才能找到最適合的方案。

下一篇文章將會介紹螞蟻金服在分散式事務上,經過多年發展,服務於內外部大量不同業務,沉澱出的一整套分散式事務產品和多種解決方案。

公眾號:金融級分散式架構(Antfin_SOFA)


推薦閱讀:

聊聊分散式

TAG:分散式事務 | 分散式系統 |