微服務架構下分佈式事務解決方案(保障分佈式事務一致性GTS)

微服務倡導將複雜的單體應用拆分爲若干個功能簡單的、松耦合的服務,這樣可以降低開發難度、增強擴展性、便於敏捷開發。概念2012年提出迅速火遍全球,被越來越多的開發者推崇,很多互聯網行業巨頭、開源社區等都開始了微服務的討論和實踐。根據Netflix雲架構總監Adrian Cockcrof,Hailo有160個不同服務構成,NetFlix有大約600個服務。國內方面,阿里巴巴、騰訊360、京東、58等很多互聯網公司都進行了微服務化改造。當前微服務的開發框架也有幾十種之多,比較著名的有DubboSpringCloudthriftgrpc等。

1 分佈式事務解決方案及其弊端

雖然微服務現在如火如荼,但對其實踐其實仍處於初級階段。即使互聯網巨頭的實踐也大多是試驗層面,鮮有核心業務系統微服務化的案例。而對於很多中小型互聯網公司,鑑於經驗、技術實力等問題,微服務落地更加困難。世界著名的軟件架構大師Chris Richardson《Introduction to Microservices》一文中也直接了當的指出了微服務當前存在的問題:

  • 從單體應用拆分爲分佈式系統帶來的複雜性。開發者需要選擇或實現基於消息或者RPC模式的進程間通訊機制,另外開發者也要寫額外的代碼去處理對於目的服務請求可能存在的請求緩慢或者請求不可用導致的局部故障問題。
  • 單體應用拆分所導致的數據庫架構的拆分。應用更新多個業務記錄非常常見,單體應用實現也比較簡單。然而在微服務架構下,應用不得不調用多個微服務去更新多個數據庫。一般很難使用分佈式事務解決,不僅僅是因爲CAP理論,還因爲一些流行的NoSQL數據庫和Message Queue系統壓根也不支持(攤手)。最後還得繞回最終一致性方案,這個方案對開發者來講也是非常有挑戰性。
  • 測試微服務架構的應用也是更加複雜的。因爲服務之間可能有諸多調用,測試一個服務將不得不啓動其他服務。
  • 部署、運維一個微服務架構的應用變的更加困難。微服務一般由大量的服務組成,每個服務還有多個運行實例!將會有更多變化的部分需要去配置、部署、擴展、監控。此外還需要實現一個服務發現機制讓其他服務找到它需要通信的服務的地址。

對於第一和第三個問題,筆者認爲隨着RPC框架的成熟,已經逐漸得到解決。例如dubbo可以支持rmi、hessian、http、webservice、thrift、redis等多種通訊協議,springcloud可以非常好的支持restful調用。spring體系下應用的測試也變的越來越簡單。對於第四個問題,隨着docker、devops技術的發展以及各公有云paas平臺自動化運維工具的推出,微服務的部署與運維會變得越來越容易。

而對於Chris Richardson提到的第二個問題,現在還沒有通用方案很好的解決微服務產生的事務問題。分佈式事務已經成爲微服務落地最大的阻礙,也是最具挑戰性的一個技術難題。 爲此,本文將深入和大家探討微服務架構下,分佈式事務的各種解決方案,並重點爲大家解讀阿里巴巴提出的分佈式事務解決方案----GTS。該方案中提到的GTS是目前業界第一款,也是唯一的一款通用的解決微服務分佈式事務問題的中間件,而且可以保證數據的強一致性

2 SOA分佈式事務解決方案

在微服務之前,信息系統中的服務大多基於SOA的理念設計(微服務和分佈式的概念、關係),服務相對比較重。對於服務調用產生的分佈式事務問題,在SOA時代,就有一些解決方案。比較著名的有基於XA協議的方案、TCC方案、消息最終一致性方案。

2.1基於XA協議的方案

該方案最早由oracle提出用於解決跨數據訪問的事務問題,是一種強一致性的解決方案,由事務協調器和本地資源管理器共同完成。事務協調器和資源管理器間通過XA協議進行通信。XA協議實現的原理入下圖所示,共分爲兩個階段,也就是我們常說的兩階段協議。

兩階段方案在解決數據庫分佈式事務問題方面應用非常廣泛,oracle、Mysql等主流關係數據庫均支持XA協議,而且ocenbase、DCDB等著名的分佈式數據庫也都基於兩階段協議。在解決服務事務問題上,其實 XA協議不是隻能作用於單個服務內部的多資源場景,跨服務的多資源場景也是可以的,只不過需要額外的事務傳遞機制。但其都有致命的缺點,性能不理想。由於需要等到各分支事務都就緒後全局事務纔開始提交,所以每個事務鎖定數據的時間較長,XA方案因此很難滿足高併發場景。而且在解決微服務問題時XA方案的性能問題將會被放大。因爲應用在訪問服務的調用方式、網絡環境等要比訪問數據庫複雜的多。例如,應用和其訪問的數據庫通常在一個局域網中,而其通過rpc調用的服務則可能屬於另一個網絡或者在公網上,其時延更長、出故障的概率更高。這將導致數據鎖定時間和系統併發度進一步降低。所以XA方案基本不適合解決微服務的事務問題。

2.2TCC方案

TCC方案應用是目前呼聲最高,也是落地最多的一個方案。當前也有一些開源的TCC框架實現,如TCC-TransactionByteTCC。TCC方案其實是兩階段方案的一種改進,其將本地資源管理器的功能融入到了業務實現中。其將整個業務邏輯顯示的分成了Try、Confirm、Cancel三部分。try部分完成業務的準備工作,confirm部分完成業務的提交,cancel部分完成事務的回滾。基本原理如下圖所示。

事務開始時,業務應用會向事務協調器註冊啓動事務。之後業務應用會調用所有服務的try接口,相當於XA的第一階段。如果有任何一個服務的try接口調用失敗會向事務協調器發送事務回滾請求,否則發送事務提交請求。事務協調器收到事務回滾請求後會依次調用事務的confirm接口,否則調用cancel接口回滾,這相當於XA的第二階段。如果第二階段接口調用失敗,會進行重試。

TCC方案通過通過三個接口很好的規避了長時間數據加鎖的問題,業務表在每個接口調用完畢即可釋放,這很大程度上提高了業務的併發度,這也是TCC方案最大的優勢。所以在SOA時期,TCC方案被很多金融、電商的業務系統大量使用。
當然TCC方案也有不足之處,集中表現在以下兩個方面:

  • 開發工作量大。它將部分資源管理器的功能融入到每個服務的開發中,導致服務的每個接口都需要實現try、confirm、cancle,還需要實現事務協調器,開發量不只翻了一倍。
  • 實現難度大。系統需要記錄每個應用的服務調用鏈路。我前面講過rpc調用情況比較複雜,由於網絡狀況、系統故障等調用失敗被視爲常態,必須按照不同的失敗原因實現不同策略的回滾。爲了滿足一致性的要求,二階段不管調用confirm還是cancle都必須調用成功,如果一次調用不成功,事務協調器必須嘗試重試。這就要求confirm和cancle接口必須實現冪等。

上述原因導致TCC方案大多是被研發實力較強、有迫切需求的大公司所採用。其將分佈式事務變成一種所謂的“貴族技術”,中小型企業由於人員有限、技術實力薄弱,很難落地。而且筆者認爲微服務倡導的是服務的輕量化、易部署,而TCC方案將很多事務的處理功能融入到業務中,對業務侵入性太高,導致服務邏輯複雜,比較適合比較重的服務。

2.3 消息事務一致性方案

消息一致性方案是通過消息中間件保證上、下游應用數據操作的一致性。基本思路是將本地操作和發送消息放在一個事務中,保證本地操作和消息發送要麼兩者都成功或者都失敗。下游應用向消息系統訂閱該消息,收到消息後執行相應操作。
以下單業務爲例進行說明,下單基本流程是先存儲訂單信息,然後扣相應商品的庫存,兩個操作必須在一個事務中。如下圖,業務應用首先調用訂單服務,訂單存儲成功後,訂單服務會通過消息處理服務投遞訂單消息到MQ。庫存服務從MQ收到消息後進行扣庫存操作,如果執行成功會向消息處理服務發送通知。消息處理服務會實時監測訂單消息是否超時,如果超時會重新投遞到MQ中,以驅動庫存服務進行扣庫存操作。如果扣庫存操作執行失敗後,庫存服務後續還會從MQ接收到相同的訂單消息,需要多次重複執行,直到成功或者進行人工干預。庫存服務需要實現冪等。

消息方案從本質上講是將分佈式事務轉換爲兩個本地事務,然後依靠下游業務的重試機制達到最終一致性。相對TCC方案來講,消息方案技術難度相對低,落地較容易,如果對一致性不敏感的應用也是一個不錯的選擇。美國著名電商e-bay以及國內的蘑菇街都做過嘗試。消息一致性方案的不足之處是其對應用侵入性較高,應用需要基於消息接口進行改造,而且需要建設專門的消息系統,成本較高。

3 GTS--微服務分佈式事務解決方案

GTS是一款分佈式事務中間件,由阿里巴巴中間件部門研發,可以爲微服務架構中的分佈式事務提供一站式解決方案。GTS方案的基本思路是:將分佈式事務與具體業務分離,在平臺層面開發通用的事務中間件GTS,由事務中間件協調各服務的調用一致性,負責分佈式事務的生命週期管理、服務調用失敗的自動回滾。

GTS方案有三方面的優勢,首先它將微服務從分佈式事務中解放出來,微服務的實現不需要再考慮反向接口、冪等、回滾策略等複雜問題,只需要業務自己的接口即可,大大降低了微服務開發的難度與工作量。將分佈式事務從所謂的“貴族技術”變爲大家都能使用的“平民技術 ”,有利於微服務的落地與推廣。 其次,GTS對業務代碼幾乎沒有侵入,只需要通過註解@TxcTransaction界定事務邊界即可,微服務接入GTS的成本非常低。第三,性能方面GTS也非常優秀,是傳統XA方案的8~10倍。

3.1 基本原理

GTS中間件主要包括客戶端(GTS Client)、資源管理器(GTS RM)和事務協調器(GTS Server)三部分。GTS Client主要完成事務的發起與結束。GTS RM完成分支事務的開啓、提交、回滾等操作。GTS Server主要負責分佈式事務的整體推進,事務生命週期的管理。

GTS和微服務集成後的結構圖如上圖所示。GTS Client需要和業務應用集成部署,RM與微服務集成部署。當業務應用發起服務調用時,首先會通過GTS Client向TC註冊新的全局事務。之後GTS Server會給業務應用返回全局唯一的事務編號xid。業務應用調用服務時會將xid傳播到服務端。微服務在執行數據庫操作時會通過GTS RM向GTS Server註冊分支事務,並完成分支事務的提交。如果A、B、C三個服務均調用成功,GTS Client會通知GTS Server結束事務。假設C調用失敗,GTS Client會要求GTS Server發起全局回滾。然後由各自的RM完成回滾工作。

3.2 GTS的關鍵機制

  • 可用性
    GTS服務也是由多個節點構成的高可用集羣,可以彈性擴張,可以接收高併發的客戶端請求。可以支持跨機房部署,支持同城容災和兩地三中心容災。任何異常情況下的保證高可用。
  • 自動回滾策略
    當有微服務調用失敗時,GTS服務可以驅動各微服務的RM替微服務完成調用的回滾工作。舉個轉賬的例子,轉賬應用通常調用存款服務和扣款服務完成轉賬功能。先調用扣款服務從A賬戶扣掉100元,然後調用存款服務向B賬戶中存款100元。如果轉賬應用在調用存款服務失敗時,GTS Client會要求GTS Server發起回滾,然後通知扣款服務對應的RM,RM會直接在A賬戶增加100元。然後GTS Server通知轉賬應用回滾成功。從這個過程可以看到,在調用服務失敗後,其實微服務不用做任何工作,而是由RM替微服務執行反向操作,也很自然的避免了冪等操作。TCC方案中,事務協調器需要顯示調用微服務的反向向接口,如果反向接口調用失敗還需要不斷重試。
  • 可擴展性
    有些情況下,應用需要調用第三方系統的接口或者不是基於GTS開發的微服,GTS無法接入到這些服務的實現中。此時需要用到GTS的MT模式。GTS的MT模式可以等價於TCC模式。

MT模式預留了一階段和二階段的提交接口,允許應用介入GTS的兩階段提交。應用將提交及回滾接口註冊後,GTS會自動完成調用。

  • 隔離級別
    GTS目前支持讀未提交和讀已提交兩種隔離級別。

3.3 GTS與其他方案的對比

1. 和XA方案對比

相比XA方案,GTS更加通用,可以對上層業務屏蔽底層實現細節,對業務幾乎沒有侵入。這一點在微服務時代特別有用,微服務面對的是大量的中小企業,甚至是個人開發者,業務訴求不盡相同,普適、標準的分佈式事務產品是非常有必要的,可以讓開發者從底層技術細節中脫離出來,更專注於業務邏輯的實現,從而獲得更高效、快速的業務發展。兩個方案都可以遵循ACID特性,都可以實現事務的強一致性。GTS性能要比XA方案高。

2. 和TCC方案對比

GTS方案和TCC方案最大的區別是實現分佈式事務實現的層面不同。TCC方案選擇從業務層面實現分佈式事務功能,將事務的回滾、重試等功能在微服務中實現。而GTS選擇從中間件層面解決分佈式事務問題,對微服務幾乎無侵入。兩個方案都可以獲得比較好的性能,都可以保證調用的一致性。TCC方案實現難度比較大,適合技術實力較強的團隊。GTS方案可以實現事務的強一致性,另外採用GTS方案後微服務會更簡單,耦合性也非常低。TCC主要提供開發框架,實現需要依賴業務方,而GTS是完整的分佈式事務解決方案,所有分佈式事務問題不需要業務方介入。

3. 和消息最終一致性對比

相比消息方案,GTS方案侵入性非常低,可以實現數據的強一致性。採用消息方案,上下游服務之間有很強的耦合性,測試、部署都不是很方便,需要單獨建設消息系統。不過消息方案實現相對簡單,如果對一致性要求不高,也是一個選擇。

3.4 GTS的應用場景

GTS可應用在涉及服務調用的多個領域,包括但不限於金融支付、電信、電子商務、快遞物流、廣告營銷、社交、即時通信、手遊、視頻、物聯網、車聯網等,詳細介紹可以閱讀 《GTS--阿里巴巴分佈式事務全新解決方案》一文。

3.5 GTS的輸出形式

GTS目前有三種輸出形式:通過公有云平臺輸出、通過公網雲服務輸出、通過專有云平臺輸出。

  • 1 通過公有云平臺輸出

這種輸出形式主要面向阿里雲用戶。如果用戶的業務系統已經部署到阿里雲上,可以直接申請開通公有云GTS。開通後業務應用即可通過GTS保證服務調用的一致行。這種使用場景下,業務系統和GTS間的網絡環境比較理想,GTS能提供更低的響應時間。

公有云提供了比較豐富的與dubbo、SpringCloud等集成的樣例,可以點擊查看。

  • 2 通過公網雲服務輸出

這種輸出形式主要面向於非阿里雲的用戶,使用更加方便、靈活,業務系統只要能連接互聯網即可享受GTS提供的雲服務。在網絡抖動和閃斷的情況下,GTS仍能保證服務調用的一致性。在正常網絡環境下,以包含兩個本地事務的全局事務爲例,事務完成時間在20ms左右,業務可以輕鬆實現1000TPS以上分佈式事務,可以滿足絕大多數業務系統的需要。也可以用於本地的開發和測試 。

現在提供了sample-txc-simple和sample-txc-sample兩個樣例,sample-txc-simple是GTS的入門的基礎樣例,點擊下載後,搭建好本地的數據庫環境就可以直接運行樣例。sample-txc-dubbo是GTS和dubbo框架集成的樣例,也可以直接在本地機器運行。

  • 3 通過專有云平臺輸出

這種形式主要面向於已建設了自己專有云平臺的大用戶,GTS可以直接部署到用戶的專有云平臺上,爲專有云提供分佈式事務服務。目前國家電網公司、中國郵政、浙江菸草等特大型企業的專有云都使用GTS,保證數據一致性。

3.6 GTS的使用方式

GTS對應用的侵入性非常低,使用也非常簡單。下面以訂單存儲應用爲例說明。訂單業務應用通過調用訂單服務和庫存服務完成訂單業務,服務開發框架爲dubbo。

1 訂單業務應用

在業務函數外圍使用@TxcTransaction註解即可開啓分佈式事務。dubbo應用通過隱藏參數將GTS的事務xid傳播到服務端。

 

@TxcTransaction(timeout = 1000 * 10)
public void Bussiness(OrderServiceInterface os,StockServiceInterface ss)
{
//獲取xid
String xid = TxcContext.getCurrentXid();
//1:調用訂單服務,創建訂單
//通過dubbo的隱形參數將txcid傳到服務端
RpcContext.getContext().setAttachment("xid",xid);
int ret = os.setOrder(new Order(pid,num,new Date()));//調用訂單服務
//2:調用庫存服務,扣庫存
RpcContext.getContext().setAttachment("xid",xid);
}

2 服務端使用方式

庫存服務

public int setStock(Stock sk) {
//通過dubbo上下文獲取xid
String xid = RpcContext.getContext().getAttachment("xid");
//將事務id綁定到服務端txc的上下文
TxcContext.bind(xid,null);
//執行扣庫存操作
ret  = jdbcTemplate2.update("update stock set number = number -? where pid = ?",new Object[]{sk.getPnum(),sk.getPid()});
return ret;
}

3.7 GTS的應用情況

GTS在滿足事務ACID的前提下,普通配置的單服務器可以達到15000 TPS以上的超強性能(兩個小時完成1億多筆業務)。目前已經在淘寶、天貓、阿里影業、淘票票、阿里媽媽、1688等阿里各業務系統廣泛使用,經受了16年和17年兩年雙十一海量請求的考驗。某線上業務系統最高流量已達十萬TPS(每秒鐘10萬筆事務)。GTS在阿里雲及專有云上輸出後,有很多用戶通過GTS解決SpringCloud、Dubbo、Edas等微服務的分佈式事務問題,包括國家電網、中國郵政、中國菸草、特步、浙江公安、德邦快遞、一步共享科技等,涉及電力、物流、ETC、菸草、金融、零售、電商、共享出行等十幾個行業,得到用戶的一致認可

上圖是GTS與SpringCloud集成,應用於某共享出行系統。業務共享出行場景下,通過GTS支撐物聯網系統、訂單系統、支付系統、運維繫統、分析系統等系各統應用事務一致性,保證海量訂單和數千萬流水的交易。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章