深入了解分布式事務組件 Seata (一)

分布式事務的問題,在微服務架構中一直是難題脸候。單體應用實現(xiàn)本地事務即可穷娱,到了分布式環(huán)境,情況就變得復雜运沦。一個請求可能涉及多個服務泵额,上下游存在依賴關系,其中的一環(huán)失敗携添,需要將整個事務回滾嫁盲。筆者在去年上半年開源過一款微服務的分布式事務組件:lottor,基于可靠消息的柔性分布式事務實現(xiàn)方案烈掠。引入的 Lottor 客戶端使用比較復雜羞秤,具有業(yè)務侵入性。推廣使用的效果并不是很好向叉。阿里在今年年初開源了 Seata(原名 fescar)锥腻,引起了強烈的反響嗦董。筆者最近也在考慮改進 Lottor母谎,借學習實踐 Seata 的機會,和大家分享一下京革。

幾款開源的分布式事務組件

既有的分布式事務解決方案按照對業(yè)務侵入性分為兩類奇唤,即:對業(yè)務無侵入的和對業(yè)務有侵入的幸斥。

業(yè)務無侵入的方案

既有的主流分布式事務解決方案中,對業(yè)務無侵入的只有基于 XA 的方案(注:問題中提到的 JTA 是 XA 方案的 Java 版本)咬扇,但應用 XA 方案存在 3 個方面的問題:

  1. 要求數(shù)據(jù)庫提供對 XA 的支持甲葬。如果遇到不支持 XA(或支持得不好,比如 MySQL 5.7 以前的版本)的數(shù)據(jù)庫懈贺,則不能使用经窖。

  2. 受協(xié)議本身的約束,事務資源(數(shù)據(jù)記錄梭灿、數(shù)據(jù)庫連接)的鎖定周期長画侣。長周期的資源鎖定從業(yè)務層面來看,往往是不必要的堡妒,而因為事務資源的管理器是數(shù)據(jù)庫本身配乱,應用層無法插手。這樣形成的局面就是皮迟,基于 XA 的應用往往性能會比較差搬泥,而且很難優(yōu)化。

  3. 已經(jīng)落地的基于 XA 的分布式解決方案伏尼,都依托于重量級的應用服務器(Tuxedo/WebLogic/WebSphere 等)忿檩,這是不適用于微服務架構的。

侵入業(yè)務的方案

實際上烦粒,最初分布式事務只有 XA 這個唯一方案休溶。XA 是完備的,但在實踐過程中扰她,由于種種原因(包含但不限于上面提到的3 點)往往不得不放棄兽掰,轉而從業(yè)務層面著手來解決分布式事務問題。比如:

  • 基于可靠消息的最終一致性方案
  • TCC
  • Saga

都屬于這一類徒役。這些方案的具體機制在這里不做展開孽尽,網(wǎng)上這方面的論述文章非常多∮俏穑總之杉女,這些方案都要求在應用的業(yè)務層面把分布式事務技術約束考慮到設計中,通常每一個服務都需要設計實現(xiàn)正向和反向的冪等接口鸳吸。這樣的設計約束熏挎,往往會導致很高的研發(fā)和維護成本。

不可否認晌砾,侵入業(yè)務的分布式事務方案都經(jīng)過大量實踐驗證坎拐,能有效解決問題,在各行種業(yè)的業(yè)務應用系統(tǒng)中起著重要作用。但回到原點來思考哼勇,這些方案的采用實際上都是迫于無奈都伪。

Seata 介紹

Seata 是一款開源的分布式事務解決方案,提供高性能和簡單易用的分布式事務服務积担。

包括了集團的 TXC(云版本叫 GTS)和螞蟻金服的 TCC 兩種模式陨晶,目前 Github 上的 star 數(shù)已經(jīng)超過一萬,算是目前唯一有大廠背書的分布式事務解決方案帝璧。
TXC 在 Seata 中又叫 AT 模式先誉,意為補償方法是框架自動生成的,對用戶完全屏蔽的烁,用戶可以向使用本地事務那樣使用分布式事務谆膳,缺點是僅支持關系型數(shù)據(jù)庫(目前支持 MySQL),引入 Seata AT 的服務需要本地建表存儲 rollback_info撮躁,隔離級別默認 RU 適用場景有限漱病。

TCC 不算是新概念,很早就有了把曼,用戶通過定義 try/confirm/cancel 三個方法在應用層面模擬兩階段提交杨帽,區(qū)別在于 TCC 中 try 方法也需要操作數(shù)據(jù)庫進行資源鎖定,后續(xù)兩個補償方法由框架自動調用嗤军,分別進行資源提交和回滾注盈,這點同單純的存儲層 2PC 不太一樣。螞蟻金服向 Seata 貢獻了自己的 TCC 實現(xiàn)叙赚,據(jù)說已經(jīng)演化了十多年老客,大量應用在在金融、交易震叮、倉儲等領域胧砰。

本文目前重點關注 Seata 中的 AT 模式。

Seata 組成

Seata 設計上將整體分成三個大模塊苇瓣,即 TM尉间、RM、TC击罪,具體解釋如下:

image
  • TM(Transaction Manager):全局事務管理器哲嘲,控制全局事務邊界,負責全局事務開啟媳禁、全局提交眠副、全局回滾。

  • RM(Resource Manager):資源管理器竣稽,控制分支事務囱怕,負責分支注冊槽唾、狀態(tài)匯報,并接收事務協(xié)調器的指令光涂,驅動分支(本地)事務的提交和回滾。

  • TC(Transaction Coordinator):事務協(xié)調器拧烦,維護全局事務的運行狀態(tài)忘闻,負責協(xié)調并驅動全局事務的提交或回滾。

Seata AT 模式是基于兩階段提交模式設計的恋博,以高效且對業(yè)務零侵入的方式齐佳,解決微服務場景下面臨的分布式事務問題。

AT 模式的架構與實現(xiàn)原理介紹

分布式事務是一個全局事務债沮,由多個分支事務組成炼吴,Seata AT 模式具體包括如下兩個階段:

  • 階段1:分支(本地)事務執(zhí)行。將一個本地事務做為一個分布式事務分支疫衩,所以若干個分布在不同微服務中的本地事務共同組成了一個全局事務硅蹦,結構如下。
image
  • 階段2:分支事務提交或回滾闷煤。階段2完成的是全局事物的最終提交或回滾童芹,當全局事務中所有分支事務全部完成并且都執(zhí)行成功,這時TM會發(fā)起全局事務提交鲤拿,TC收到全全局事務提交消息后假褪,會通知各分支事務進行提交;同理近顷,當全局事務中所有分支事務全部完成并且某個分支事務失敗了生音,TM會通知TC協(xié)調全局事務回滾,進而TC通知各分支事務進行回滾窒升。

在業(yè)務應用啟動過程中缀遍,由于引入了 Seata 客戶端,RmRpcClient會隨應用一起啟動饱须,該RmRpcClient采用Netty實現(xiàn)瑟由,可以接收TC消息和向TC發(fā)送消息,因此RmRpcClient是與TC收發(fā)消息的關鍵模塊冤寿。

Seata 實現(xiàn)分布式事務的一般過程如下:

image
  • TM 通知 TC 開始一個新的全局事務歹苦。TC 生成了一個代表全局事務的 XID。
  • XID 通過微服務的調用鏈傳播下去督怜。
  • RM將本地事務注冊為XID到TC的相應全局事務的分支殴瘦。
  • TM 通知 TC 提交或者回滾 XID 對應的全局事務
  • TC 驅動 XID 的對應全局事務下的所有分支事務以完成分支提交或回滾。

Seata AT 模式使用入門

示例使用 seata-samples 中的 Seata-JPA 項目号杠。

涉及到的幾個服務如下所示:

image

客戶端發(fā)起業(yè)務服務蚪腋,Business 調用 Storage 鎖定庫存丰歌、Order 生成訂單。Order 調用 Account 扣減余額屉凯。各個服務對應的角色已經(jīng)在上圖標注立帖。

啟動 TC 服務

首先,我們啟動 Seata-Server悠砚,即 TC晓勇。下載 Seata-Server 的發(fā)行包。執(zhí)行如下命令即可啟動服務器灌旧。

sh distribution/bin/seata-server.sh -p 8091 -h 127.0.0.1 -m file

新建數(shù)據(jù)庫表

執(zhí)行幾個服務涉及到的數(shù)據(jù)庫表:

每個服務都有對應的業(yè)務表和 undo_log 表绑咱。

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

在事務鏈涉及的服務的數(shù)據(jù)庫中新建 undo_log 表用來存儲 UndoLog 信息,用于二階段回滾操作枢泰,表中包含 xid描融、branchId、rollback_info 等關鍵字段信息衡蚂。

增加全局事務注解

    @GlobalTransactional
    public void purchase(String userId, String commodityCode, int orderCount) {
        storageFeignClient.deduct(commodityCode, orderCount);

        orderFeignClient.create(userId, commodityCode, orderCount);
    }

依賴 Seata 的客戶端 SDK窿克,然后在整個分布式事務發(fā)起方的業(yè)務方法上增加 @GlobalTransactional 注解。

配置代理數(shù)據(jù)源

Seata 中主要針對 java.sql 包下的 DataSource毛甲、Connection让歼、Statement、PreparedStatement 四個接口進行了再包裝丽啡,包裝類分別為 DataSourceProxy谋右、ConnectionProxy、StatementProxy补箍、PreparedStatementProxy改执,很好一一對印,其功能是在 SQL 語句執(zhí)行前后坑雅、事務 commit 或者 rollbakc 前后進行一些與 Seata 分布式事務相關的操作辈挂,例如分支注冊、狀態(tài)回報裹粤、全局鎖查詢终蒂、快照存儲、反向 SQL 生成等遥诉。

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DruidDataSource druidDataSource() {
        return new DruidDataSource();
    }

    @Primary
    @Bean("dataSource")
    public DataSource dataSource(DruidDataSource druidDataSource) {
        return new DataSourceProxy(druidDataSource);
    }
}

需要將 DataSourceProxy 設置為主數(shù)據(jù)源拇泣,否則事務無法回滾。

驗證

業(yè)務服務中提供了兩個接口矮锈,一個正常提交霉翔,另一個回滾,執(zhí)行之后查看結果苞笨。

GET http://127.0.0.1:8084/purchase/commit
Accept: application/json

###
GET http://127.0.0.1:8084/purchase/rollback
Accept: application/json

大家可以自行驗證一下結果债朵。

小結

本文簡單介紹了阿里開源的分布式事務組件 Seata 的相關概念子眶,重點介紹了 Seata 的 AT 模式,MT 模式在后面將會介紹序芦。本文比較簡單臭杰,是一個入門的實踐。Seata 是一個優(yōu)秀的分布式事務框架谚中,筆者會在后面的文章中結合源碼介紹 Seata 的實現(xiàn)原理渴杆。

推薦閱讀

微服務合集

訂閱最新文章,歡迎關注我的公眾號

微信公眾號
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末藏杖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子脉顿,更是在濱河造成了極大的恐慌蝌麸,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件艾疟,死亡現(xiàn)場離奇詭異来吩,居然都是意外死亡,警方通過查閱死者的電腦和手機蔽莱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門弟疆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人盗冷,你說我怎么就攤上這事怠苔。” “怎么了仪糖?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵柑司,是天一觀的道長。 經(jīng)常有香客問我锅劝,道長攒驰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任故爵,我火速辦了婚禮玻粪,結果婚禮上,老公的妹妹穿的比我還像新娘诬垂。我一直安慰自己劲室,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布结窘。 她就那樣靜靜地躺著痹籍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪晦鞋。 梳的紋絲不亂的頭發(fā)上蹲缠,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天棺克,我揣著相機與錄音,去河邊找鬼线定。 笑死娜谊,一個胖子當著我的面吹牛,可吹牛的內容都是我干的斤讥。 我是一名探鬼主播纱皆,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼芭商!你這毒婦竟也來了派草?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤铛楣,失蹤者是張志新(化名)和其女友劉穎近迁,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體簸州,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡鉴竭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了岸浑。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搏存。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖矢洲,靈堂內的尸體忽然破棺而出璧眠,到底是詐尸還是另有隱情,我是刑警寧澤读虏,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布蛆橡,位于F島的核電站,受9級特大地震影響掘譬,放射性物質發(fā)生泄漏泰演。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一葱轩、第九天 我趴在偏房一處隱蔽的房頂上張望睦焕。 院中可真熱鬧,春花似錦靴拱、人聲如沸垃喊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽本谜。三九已至,卻和暖如春偎窘,著一層夾襖步出監(jiān)牢的瞬間乌助,已是汗流浹背溜在。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留他托,地道東北人掖肋。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像赏参,于是被迫代替她去往敵國和親志笼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內容

  • Seata框架是一個業(yè)務層的XA(兩階段提交)解決方案把篓。在理解Seata分布式事務機制前纫溃,我們先回顧一下數(shù)據(jù)庫層面...
    伊凡的一天閱讀 102,529評論 18 92
  • 左眼看世界 因為我的右眼已模糊不清 推開門 門外的風景分外迷人 那是右眼模糊的影子替左眼高興 關上門 左眼呆呆地望...
    喵個CC閱讀 604評論 0 0
  • 總有一個時間段,非常想哭 非常的想被愛護 并沒有說的出口的悲傷故事 就是情緒很難自抑 降低期望值 放過自己 對不起
    拾荒小筑閱讀 124評論 0 0
  • 勞動力之所以廉價韧掩,是因為你沒有滿足人最主要的需求紊浩。 你雖然滿足了需求,但是供應方太多了揍很。你就廉價了郎楼。
    閑聽急雨打芭蕉閱讀 248評論 0 1
  • 我的簡書万伤,日更百天之后窒悔,便泡湯了。不會熬夜的我日更之后幾乎每天熬夜敌买,最終使得每天下午就可以頭疼简珠,神經(jīng)衰弱的厲害。甚...
    陽春白雪888閱讀 230評論 2 6