深入解讀微服務架構下分散式事務解決方案

一、微服務的發展

微服務倡導將複雜的單體應用拆分為若干個功能簡單、松耦合的服務,這樣可以降低開發難度、增強擴充套件性、便於敏捷開發。當前被越來越多的開發者推崇,很多網際網路行業巨頭、開源社群等都開始了微服務的討論和實踐。Hailo有160個不同服務構成,NetFlix有大約600個服務,國內方面,阿里巴巴、騰訊、360、京東、58同城等很多網際網路公司都進行了微服務化實踐。當前微服務的開發框架也非常多,比較著名的有Dubbo、SpringCloud、thrift 、grpc等。

二、微服務落地存在的問題

雖然微服務現在如火如荼,但實踐其實仍處於探索階段。很多中小型網際網路公司,鑑於經驗、技術實力等問題,微服務落地比較困難。如著名架構師Chris Richardson所言,目前存在的主要困難有如下幾方面:

單體應用拆分為分散式系統後,程序間的通訊機制和故障處理措施變的更加複雜。

系統微服務化後,一個看似簡單的功能,內部可能需要呼叫多個服務並操作多個數據庫實現,服務呼叫的分散式事務問題變的非常突出。

微服務數量眾多,其測試、部署、監控等都變的更加困難。

隨著RPC框架的成熟,第一個問題已經逐漸得到解決。例如,dubbo可以支援多種通訊協議,springcloud可以非常好的支援restful呼叫;對於第三個問題,隨著docker、devops技術的發展以及各公有云paas平臺自動化運維工具的推出,微服務的測試、部署與運維會變得越來越容易。

而對於第二個問題,現在還沒有通用方案很好地解決微服務產生的事務問題。分散式事務已經成為微服務落地最大的阻礙,也是最具挑戰性的一個技術難題。 為此,本文將深入和大家探討微服務架構下,分散式事務的各種解決方案,並重點為大家解讀阿里巴巴提出的分散式事務解決方案——GTS。

該方案中提到的GTS是全新一代解決微服務問題的分散式事務網際網路中介軟體

深入解讀微服務架構下分散式事務解決方案

三、SOA分散式事務解決方案

3.1 基於XA協議的兩階段提交方案

交易中介軟體與資料庫透過 XA 介面規範,使用兩階段提交來完成一個全域性事務, XA 規範的基礎是兩階段提交協議。

第一階段是表決階段,所有參與者都將本事務能否成功的資訊反饋發給協調者;第二階段是執行階段,協調者根據所有參與者的反饋,通知所有參與者,步調一致地在所有分支上提交或者回滾。

深入解讀微服務架構下分散式事務解決方案

基於XA協議的兩階段提交方案

兩階段提交方案應用非常廣泛,幾乎所有商業OLTP資料庫都支援XA協議。但是兩階段提交方案鎖定資源時間長,對效能影響很大,基本不適合解決微服務事務問題。

3.2 TCC方案

TCC方案在電商、金融領域落地較多,TCC方案其實是兩階段提交的一種改進,將整個業務邏輯的每個分支顯式的分成了Try、Confirm、Cancel三個操作。Try部分完成業務的準備工作,confirm部分完成業務的提交,cancel部分完成事務的回滾,基本原理如下圖所示:

深入解讀微服務架構下分散式事務解決方案

TCC方案事務開始時,業務應用會向事務協調器註冊啟動事務。之後業務應用會呼叫所有服務的try介面,完成一階段準備。之後事務協調器會根據try介面返回情況,決定呼叫confirm介面或者cancel介面。如果介面呼叫失敗,會進行重試。

TCC方案讓應用自己定義資料庫操作的粒度,使得降低鎖衝突、提高吞吐量成為可能。 當然TCC方案也有不足之處,集中表現在以下兩個方面:

對應用的侵入性強

。業務邏輯的每個分支都需要實現try、confirm、cancel三個操作,應用侵入性較強,改造成本高。

實現難度較大

。需要按照網路狀態、系統故障等不同的失敗原因實現不同的回滾策略。為了滿足一致性的要求,confirm和cancel介面必須實現冪等。

上述原因導致TCC方案大多被研發實力較強、有迫切需求的大公司所採用。微服務倡導服務的輕量化、易部署,而TCC方案中很多事務的處理邏輯需要應用自己編碼實現,複雜且開發量大。

3.3 基於訊息的最終一致性方案

訊息一致性方案是透過訊息中介軟體保證上、下游應用資料操作的一致性。基本思路是將本地操作和傳送訊息放在一個事務中,保證本地操作和訊息傳送要麼兩者都成功或者都失敗。下游應用向訊息系統訂閱該訊息,收到訊息後執行相應操作。

深入解讀微服務架構下分散式事務解決方案

訊息一致性方案

訊息方案從本質上講是將分散式事務轉換為兩個本地事務,然後依靠下游業務的重試機制達到最終一致性。基於訊息的最終一致性方案對應用侵入性也很高,應用需要進行大量業務改造,成本較高。

為了幫助大家少走彎路,我請BAT大廠工作的同事總結出一套技術影片,涵蓋Java工程化、高效能及分散式、效能調優、Spring、Netty原始碼分析和大資料等知識點,想要了解詳情的可以加入

Java後端技術群:819940388

,免費的大型網際網路Java技術影片分享給大家。其實我自己也比較喜歡技術,群裡有一些阿里大牛,也有一線網際網路的資深HR,最近在面試的朋友或者在找工作的可以進來看看!

深入解讀微服務架構下分散式事務解決方案

四、GTS--分散式事務解決方案

GTS是一款分散式事務中介軟體,由阿里巴巴中介軟體部門研發,可以為微服務架構中的分散式事務提供一站式解決方案。

4.1 GTS的核心優勢

1、效能超強

GTS透過大量創新,解決了事務ACID特性與高效能、高可用、低侵入不可兼得的問題。單事務分支的平均響應時間在2ms左右,3臺伺服器組成的叢集可以支撐3萬TPS以上的分散式事務請求。

2、應用侵入性極低

GTS對業務低侵入,業務程式碼最少只需要新增一行註解(@TxcTransaction)宣告事務即可。業務與事務分離,將微服務從事務中解放出來,微服務關注於業務本身,不再需要考慮反向介面、冪等、回滾策略等複雜問題,極大降低了微服務開發的難度與工作量。

3、完整解決方案

GTS支援多種主流的服務框架,包括EDAS,Dubbo,Spring Cloud等。

有些情況下,應用需要呼叫第三方系統的介面,而第三方系統沒有接入GTS。此時需要用到GTS的MT模式。GTS的MT模式可以等價於TCC模式,使用者可以根據自身業務需求自定義每個事務階段的具體行為。MT模式提供了更多的靈活性,可能性,以達到特殊場景下的自定義最佳化及特殊功能的實現。

4、容錯能力強

GTS解決了XA事務協調器單點問題,實現真正的高可用,可以保證各種異常情況下的嚴格資料一致。

4.2 GTS的應用場景

GTS可應用在涉及服務呼叫的多個領域,包括但不限於金融支付、電信、電子商務、快遞物流、廣告營銷、社交、即時通訊、手遊、影片、物聯網、車聯網等。

4.3 GTS與微服務的整合

GTS包括客戶端(GTS Client)、資源管理器(GTS RM)和事務協調器(GTS Server)三個部分。GTS Client主要用來界定事務邊界,完成事務的發起與結束;GTS RM完成事務分支的建立、提交、回滾等操作;GTS Server主要負責分散式事務的整體推進,事務生命週期的管理。GTS和微服務整合的結構圖如下所示,GTS Client需要和業務應用整合部署,RM與微服務整合部署。

深入解讀微服務架構下分散式事務解決方案

4.4 GTS的輸出形式

GTS目前有三種輸出形式:公有云輸出、公網輸出、專有云輸出。

(1) 公有云輸出

這種輸出形式面向阿里雲使用者。如果使用者的業務系統已經部署到阿里雲上,可以申請開通公有云GTS。開通後業務應用即可透過GTS保證服務呼叫的一致性。這種使用場景下,業務系統和GTS間的網路環境比較理想,達到很好效能。

深入解讀微服務架構下分散式事務解決方案

(2) 公網輸出

這種輸出形式面向於非阿里雲的使用者,使用更加方便、靈活,業務系統只要能連線網際網路即可享受GTS提供的雲服務(與公有云輸出的差別在於客戶端部署於使用者本地,而不在雲上)。

在正常網路環境下,以包含兩個本地事務的全域性事務為例,事務完成時間在20ms左右,50個併發就可以輕鬆實現1000TPS以上分散式事務,對絕大多數業務來說效能是足夠的。在公網環境,網路閃斷很難完全避免,這種情況下GTS仍能保證服務呼叫的資料一致性。

深入解讀微服務架構下分散式事務解決方案

(3)專有云輸出

這種形式主要面向於已建設了自己專有云平臺的大使用者,GTS可以直接部署到使用者的專有云上,為專有云提供分散式事務服務。目前已經有10多個特大型企業的專有云使用GTS解決分散式事務難題,效能與穩定性經過了使用者的嚴格檢測。

4.5 GTS的使用方式

GTS對應用的侵入性非常低,使用也很簡單。下面以訂單儲存應用為例說明。訂單業務應用透過呼叫訂單服務和庫存服務完成訂單業務,服務開發框架為Dubbo。

(1)訂單業務應用

在業務函式外圍使用@TxcTransaction註解即可開啟分散式事務。Dubbo應用透過隱藏引數將GTS的事務xid傳播到服務端。

@TxcTransaction(timeout = 1000 * 10)public void Bussiness(OrderService orderService, StockService stockService, String userId) { //獲取事務上下文 String xid = TxcContext。getCurrentXid(); //透過RpcContext將xid傳到一個服務端 RpcContext。getContext()。setAttachment(“xid”, xid); //執行自己的業務邏輯 int productId = new Random()。nextInt(100); int productNum = new Random()。nextInt(100); OrderDO orderDO = new OrderDO(userId, productId, productNum, new Timestamp(new Date()。getTime())); orderService。createOrder(orderDO); //透過RpcContext將xid傳到另一個服務端 RpcContext。getContext()。setAttachment(“xid”,xid); stockService。updateStock(orderDO);}

(2) 服務提供者

更新庫存方法

public int updateStock(OrderDO orderDO) { //獲取全域性事務ID,並繫結到上下文 String xid = RpcContext。getContext()。getAttachment(“xid”); TxcContext。bind(xid,null); //執行自己的業務邏輯 String sql = “update stock set amount = amount - ? where product_id = ?”; int ret = jdbcTemplate。update(sql,new Object[]{orderDO。getNumber(), orderDO。getProductId()}); TxcContext。unbind(); return ret;}

4.6 GTS的應用情況

GTS目前已經在淘寶、天貓、阿里影業、淘票票、阿里媽媽、1688等阿里各業務系統廣泛使用,經受了16年和17年兩年雙十一海量請求的考驗。某線上業務系統最高流量已達十萬TPS(每秒鐘10萬筆事務)。

GTS在公有云和專有云輸出後,已經有了100多個線上使用者,很多使用者透過GTS解決SpringCloud、Dubbo、Edas等服務框架的分散式事務問題。業務領域涉及電力、物流、ETC、菸草、金融、零售、電商、共享出行等十幾個行業,得到使用者的一致認可。

深入解讀微服務架構下分散式事務解決方案

GTS與springCloud整合案例

上圖是GTS與SpringCloud整合,應用於某共享出行系統。業務共享出行場景下,透過GTS支撐物聯網系統、訂單系統、支付系統、運維繫統、分析系統等系各統應用的資料一致性,保證海量訂單和數千萬流水的交易。4。7 GTS的工程樣例

GTS的公有云樣例可參考阿里雲網站。在公網環境下提供sample-txc-simple和sample-txc-dubbo兩個樣例工程。(點選下載)

注意

mysql-connector-java 的版本需要和 MySQL 資料庫版本匹配。樣例 pom。xml 中推薦的 5。1。38 版本已經在 5。0。55、5。6。16、5。6。21 三個 MySQL 資料庫版本上執行過。

MySQL 資料庫的庫名、表名和欄位名需要設定為大小寫不敏感。

sample-txc-dubbo樣例使用 Multicast 註冊中心的宣告方式。如果本機使用無線網路,Dubbo 服務在繫結地址時有可能獲取 IPv6 地址,可以透過 JVM 啟動引數禁用。方法是配置 JVM 啟動引數 -Djava。net。preferIPv4Stack=true。

4.7 sample-txc-simple樣例

(1)樣例業務邏輯

該樣例是GTS的入門sample,案例的業務邏輯是從A賬戶轉賬給B賬戶,其中A和B分別位於兩個MySQL資料庫中,使用GTS事務保證A和B賬戶錢的總數始終不變。

(2)樣例搭建方法

準備本地資料庫環境

準備一臺能連線公網的電腦,配置 Java 環境和 Maven 環境。

安裝 MySQL 資料庫軟體,並建立兩個資料庫 db1 和 db2。

在 db1 和 db2 中分別建立 txc_undo_log 表。

在 db1 庫中建立 user_money_a 表,在 db2 庫中建立 user_money_b 表

下載樣例

將sample-txc-simple(點選下載)檔案下載到本地,樣例中已經包含了GTS的SDK。

修改配置

資料來源配置:

開啟sample-txc-simple/src/main/resources目錄下的txc-client-context。xml,將資料來源的url、username、password修改為實際值。

scanner配置

將 txc-client-context。xml 中的 scanner 配置修改為:

編譯樣例

Mac OS 或 Linux 系統

在 sample-txc-simple 目錄下執行 build。sh 命令。

Windows 系統

在 sample-txc-simple 目錄下執行 build。bat 命令。

執行樣例

Mac OS 或 Linux 系統

在 txc-yun-sample/sample-txc-simple/client/bin 目錄下執行 run。sh 命令。

Windows 系統

啟動 cmd。exe,在 txc-yun-sample/sample-txc-simple/client/bin 目錄下執行 start。bat 命令。

(2)樣例業務邏輯

本案例模擬了使用者下訂單、減庫存的業務邏輯。客戶端(Client)透過呼叫訂單服務(OrderService)建立訂單,之後透過呼叫庫存服務(StockService)扣庫存。其中訂單服務讀寫訂單資料庫,庫存服務讀寫庫存資料庫。由 GTS 保證跨服務事務的一致性。

(3)樣例搭建方法

準備資料庫環境

安裝MySQL,建立兩個資料庫db1和db2。在db1和db2中分別建立txc_undo_log表。在db1庫中建立orders表,在db2庫中建立stock表。

下載樣例

將樣例檔案(點選下載)下載到本地機器,樣例中已經包含了GTS的SDK。

修改配置

資料來源配置

開啟sample-txc-dubbo/src/main/resources目錄,將dubbo-order-service。xml、dubbo-stock-service。xml兩個檔案中資料來源的url、username、password修改為實際值。

scanner配置

將 resource 目錄下的每個 xml 檔案中的 scanner 配置修改為:

編譯樣例

Mac OS 或 Linux 系統

在 sample-txc-dubbo 目錄下執行 build。sh 命令。

Windows 系統

在 sample-txc-dubbo 目錄下執行 build。bat 命令。

執行樣例

Mac OS 或 Linux 系統

在 txc-yun-sample/sample-txc-dubbo 目錄下執行 run。sh 命令。

該指令碼會依次啟動 order_run。sh(訂單服務)、stock_run。sh(庫存服務)和 client_run。sh(客戶端程式)。

Windows 系統

啟動 cmd。exe,進入 txc-yun-sample/sample-txc-dubbo/client/bin 目錄。

執行 order。bat 命令,執行訂單服務。

執行 stock。bat 命令,執行庫存服務。

訂單服務和庫存服務都啟動成功後,執行 client。bat 命令, 執行客戶端程式。

(4)SQL

1。建表 txc_undo_log

CREATE TABLE txc_undo_log (

id bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘主鍵’,

gmt_create datetime NOT NULL COMMENT ‘建立時間’,

gmt_modified datetime NOT NULL COMMENT ‘修改時間’,

xid varchar(100) NOT NULL COMMENT ‘全域性事務ID’,

branch_id bigint(20) NOT NULL COMMENT ‘分支事務ID’,

rollback_info longblob NOT NULL COMMENT ‘LOG’,

status int(11) NOT NULL COMMENT ‘狀態’,

server varchar(32) NOT NULL COMMENT ‘分支所在DB IP’,

PRIMARY KEY (id),

KEY unionkey (xid,branch_id)

) ENGINE=InnoDB AUTO_INCREMENT=211225994 DEFAULT CHARSET=utf8 COMMENT=‘事務日誌表’;

2。建表 user_money_a

CREATE TABLE user_money_a (

id int(11) NOT NULL AUTO_INCREMENT,

money int(11) DEFAULT NULL,

PRIMARY KEY (id)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

3。建表 user_money_b

CREATE TABLE user_money_b (

id int(11) NOT NULL AUTO_INCREMENT,

money int(11) DEFAULT NULL,

PRIMARY KEY (id)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

4。建表 orders

CREATE TABLE orders (

id bigint(20) NOT NULL AUTO_INCREMENT,

user_id varchar(255) NOT NULL,

product_id int(11) NOT NULL,

number int(11) NOT NULL,

gmt_create timestamp NOT NULL,

PRIMARY KEY (id)

) ENGINE=MyISAM AUTO_INCREMENT=351 DEFAULT CHARSET=utf8

5。建表 stock

CREATE TABLE stock (

product_id int(11) NOT NULL,

price float NOT NULL,

amount int(11) NOT NULL,

PRIMARY KEY (product_id)

) ENGINE=InnoDB DEFAULT CHARSET=utf8

隨著IT培訓業的持續發展和大量的應屆畢業生進入社會,Java程式設計師面臨的競爭壓力越來越大。那麼,作為一名Java程式設計師,怎樣努力才能快速成長為一名高階的程式設計師或者架構師,或者說一名優秀的高階架構師應該有怎樣的技術知識體系,這不僅是一個剛剛踏入職場的初級程式設計師,也是工作三五年之後開始迷茫的老程式設計師,都必須要面對和想明白的問題。

後臺私信回覆“架構” 即可免費獲得一套價值一萬六的內部教材!