分布式事務(wù)框架seata原理

分布式事務(wù)框架seata原理

Seata簡(jiǎn)介

Seata(原名Fescar) 是阿里18年開源的分布式事務(wù)的框架。Fescar的開源對(duì)分布式事務(wù)框架領(lǐng)域影響 很大。作為開源大戶幸逆,F(xiàn)escar來(lái)自阿里的GTS,經(jīng)歷了好幾次雙十一的考驗(yàn)晰房,一經(jīng)開源便頗受關(guān)注柠新。同時(shí)Fescar也保留了接近0業(yè)務(wù)入侵的優(yōu)點(diǎn)窍荧,只需要簡(jiǎn)單的配置Fescar的數(shù)據(jù)代理和加個(gè)注解,加一個(gè) Undolog表恨憎,就可以達(dá)到我們想要的目的蕊退。

Seata原理

seata將一個(gè)本地事務(wù)作為一個(gè)分布式事務(wù)的分支,若干個(gè)分支分布在不同的微服務(wù)上,組成一個(gè)全局事務(wù).seata包含三個(gè)結(jié)構(gòu):

Transaction Coordinator (TC): 事務(wù)協(xié)調(diào)器,維護(hù)全局事務(wù)的運(yùn)行狀態(tài) ,負(fù)責(zé)協(xié)調(diào)驅(qū)動(dòng)全局事務(wù)的提交或者回滾.

Transaction Manager (TM): 控制全局事務(wù)的邊界憔恳,負(fù)責(zé)開啟一個(gè)全局事務(wù)瓤荔,并最終發(fā)起全局提交或全局回滾的決議。

Resource Manager (RM): 控制分支事務(wù)钥组,負(fù)責(zé)分支注冊(cè)输硝、狀態(tài)匯報(bào),并接收事務(wù)協(xié)調(diào)器的指令程梦,驅(qū)動(dòng)分支(本地)事務(wù)的提交和回滾点把。

其中TM向TC申請(qǐng)一個(gè)全局事務(wù),并生成一個(gè)全局唯一的XID.XID會(huì)在全局事務(wù)調(diào)用分支事務(wù)時(shí)在調(diào)用鏈路的上下文中傳播,RM會(huì)攜帶XID向TC申請(qǐng)注冊(cè)分支事務(wù),TC調(diào)度XID下的所有分支事務(wù)的提交和回滾.

批注 2020-08-04 194555.jpg

一個(gè)典型的分布式事務(wù)過(guò)程:

  1. TM 向 TC 申請(qǐng)開啟一個(gè)全局事務(wù),全局事務(wù)創(chuàng)建成功并生成一個(gè)全局唯一的 XID屿附。

  2. XID 在微服務(wù)調(diào)用鏈路的上下文中傳播郎逃。

  3. RM 向 TC 注冊(cè)分支事務(wù),將其納入 XID 對(duì)應(yīng)全局事務(wù)的管轄,并會(huì)執(zhí)行分支事務(wù)并提交(RM在第一階段就已經(jīng)執(zhí)行了本地事務(wù)的提交或回滾),最后將執(zhí)行結(jié)果匯報(bào)給TC

  4. TM根據(jù)TC中的分支事務(wù)執(zhí)行情況 向 TC 發(fā)起針對(duì) XID 的全局提交或回滾決議挺份。

  5. TC 調(diào)度 XID 下管轄的全部分支事務(wù)完成提交或回滾請(qǐng)求衣厘。

Seata模式

seata提供了三種實(shí)現(xiàn)分布式事務(wù)的模式:AT模式,MT模式和混合模式

AT模式

業(yè)務(wù)邏輯不需要關(guān)注事務(wù)機(jī)制,分支與全局事務(wù)的交互過(guò)程自動(dòng)進(jìn)行。

AT****模式:主要關(guān)注多 DB 訪問(wèn)的數(shù)據(jù)一致性影暴,實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單错邦,對(duì)業(yè)務(wù)的侵入較小。AT模式部分代碼如下:不需要關(guān)注執(zhí)行狀態(tài)型宙,對(duì)業(yè)務(wù)代碼侵入較小撬呢。類似代碼如下,只需要為方法添 加 @GlobalTransactional 注解即可妆兑。

AT模式的核心是對(duì)業(yè)務(wù)無(wú)侵入魂拦,是一種改進(jìn)后的兩階段提交.

詳細(xì)流程

第一階段

第一步:解析sql語(yǔ)句,得到 SQL 的類型(UPDATE)搁嗓,表(product)芯勘,條件(where name = 'TXC')等相關(guān)的信息。

第二步:查詢老數(shù)據(jù)腺逛,根據(jù)上面的where語(yǔ)句sql荷愕,去數(shù)據(jù)庫(kù)查詢?cè)嫉臄?shù)據(jù)。

如 select * from product where name = 'TXC';得到原始的數(shù)據(jù)棍矛,如該行id=1安疗,然后記錄下來(lái)。

第三步:執(zhí)行第一步的sql語(yǔ)句够委,即執(zhí)行update荐类,修改數(shù)據(jù)庫(kù)的該記錄的值。

第四步:查詢修改后的值茁帽,select * from product where id =1.得到該行值玉罐,記錄下來(lái)。

第五步:插入回滾日志潘拨,將老值吊输、新值以及sql語(yǔ)句組成一個(gè)將來(lái)可用于回滾的日志,插入到UNDO_LOG表战秋。

{
    "branchId": 641789253,
    "undoItems": [{
        "afterImage": {        //更新后的數(shù)據(jù)
            "rows": [{
                "fields": [{
                    "name": "id",
                    "type": 4,
                    "value": 1
                }, {
                    "name": "name",
                    "type": 12,
                    "value": "GTS"
                }, {
                    "name": "since",
                    "type": 12,
                    "value": "2014"
                }]
            }],
            "tableName": "product"   //數(shù)據(jù)表名
        },
        "beforeImage": {  //更新前的數(shù)據(jù)
            "rows": [{
                "fields": [{
                    "name": "id",
                    "type": 4,
                    "value": 1
                }, {
                    "name": "name",
                    "type": 12,
                    "value": "TXC"
                }, {
                    "name": "since",
                    "type": 12,
                    "value": "2014"
                }]
            }],
            "tableName": "product"   //數(shù)據(jù)表名
        },
        "sqlType": "UPDATE"  //sql語(yǔ)句類型
    }],
    "xid": "xid:xxx"  //全局事務(wù)id
}

第六步:向TC server注冊(cè)分支璧亚,申請(qǐng)product表,id=1的行的全局鎖脂信。注意癣蟋,這個(gè)全局鎖是相對(duì)于所有可能的同時(shí)在執(zhí)行的分布式事務(wù)而言的。一旦某個(gè)分支狰闪,獲取了該記錄的全局鎖疯搅,在解鎖之前,任何其他的分布式事務(wù)埋泵,不能修改該數(shù)據(jù)幔欧。

第七步:本地事務(wù)提交罪治,將自己的本地事務(wù)、和前面的UNDO LOG一起提交礁蔗。

第八步:將本地事務(wù)提交的結(jié)果上報(bào)給TC server觉义。如成功、失敗浴井。

第二階段

成功的情況:分支收到了TC下發(fā)的成功請(qǐng)求晒骇,立馬返回我已OK的結(jié)果給TC,然后異步執(zhí)行刪除UNDO LOG的操作磺浙。因?yàn)槌晒α撕槎冢杂脕?lái)回滾的UNDO LOG就沒意義了,異步刪除掉就好撕氧。

失敗的情況:

1 分支收到了TC下發(fā)的失敗請(qǐng)求瘤缩,開始執(zhí)行回滾邏輯。

2 通過(guò) XID 和 Branch ID 查找到相應(yīng)的 UNDO LOG 記錄伦泥。

3 數(shù)據(jù)校驗(yàn):拿 UNDO LOG 中的后鏡與當(dāng)前數(shù)據(jù)進(jìn)行比較剥啤,如果有不同,說(shuō)明數(shù)據(jù)被當(dāng)前全局事務(wù)之外的動(dòng)作做了修改奄喂。這種情況铐殃,需要根據(jù)配置策略來(lái)做處理海洼,詳細(xì)的說(shuō)明在另外的文檔中介紹跨新。

4 根據(jù) UNDO LOG 中的前鏡像和業(yè)務(wù) SQL 的相關(guān)信息生成并執(zhí)行回滾的語(yǔ)句。

update product set name = 'TXC' where id = 1;

5 提交本地事務(wù)坏逢。并把本地事務(wù)的執(zhí)行結(jié)果(即分支事務(wù)回滾的結(jié)果)上報(bào)給 TC域帐。

結(jié)論:

可以看到,整體來(lái)說(shuō)是整,這個(gè)分布式事務(wù)是比較迅速的肖揣,在不等待全局鎖的情況下,基本和本地事務(wù)沒什么區(qū)別浮入×牛回滾時(shí),也不依賴數(shù)據(jù)庫(kù)本身的回滾能力事秀,都由自己業(yè)務(wù)來(lái)實(shí)現(xiàn)回滾操作彤断。

臟讀和臟寫

臟讀:在RM提交本地事務(wù)之后,TC提交全局事務(wù)之前,由于本地事務(wù)已提交,其他事務(wù)便可以讀取到已提交事務(wù)修改的數(shù)據(jù),但在TC回滾全局事務(wù)之后,其他事務(wù)讀取到的數(shù)據(jù)又會(huì)變?yōu)楦虑暗臄?shù)據(jù)

官方給出的解決方案為:臟讀取Select語(yǔ)句用于更新,代理方法使用@ GlobalLock + @ Transactional或@GlobalTransaction

臟寫:在TC通知分支事務(wù)回滾后,分支事務(wù)回滾之前,發(fā)現(xiàn)涉及的數(shù)據(jù)已經(jīng)被修改,無(wú)法和UNDO LOG記錄中的舊數(shù)據(jù)匹配上,則會(huì)回滾失敗!

官方給出的解決方案為: 臟寫您必須使用@globaltransaction注意:如果要查詢的業(yè)務(wù)接口不使用@globaltransactional批注易迹,這意味著該方法不需要分布式事務(wù)宰衙,則可以在該方法上批注@ globallock + @ Transactional批注方法,然后在查詢中添加for update語(yǔ)句睹欲。如果您的查詢接口在事務(wù)鏈接的外邊緣具有@globaltransactional批注供炼,則只需在查詢中添加for update語(yǔ)句即可一屋。設(shè)計(jì)此批注的原因是,在分布式注釋可用之前袋哼,分布式事務(wù)需要查詢已提交的數(shù)據(jù)冀墨,而業(yè)務(wù)則不需要分布式事務(wù)。使用GlobalTransactional批注會(huì)增加一些不必要的RPC額外開銷涛贯,例如開始返回xid轧苫,提交事務(wù)等。

@globaltransactional注解會(huì)開啟全局事務(wù)和本地事務(wù)

@ globallock 聲明事務(wù)僅執(zhí)行在本地RM中疫蔓,但是本次事務(wù)確保在更新狀態(tài)下的操作記錄不會(huì)被其他全局事務(wù)操作含懊。即將本地事務(wù)的執(zhí)行納入seata分布式事務(wù)的管理,一起競(jìng)爭(zhēng)全局鎖衅胀,保證全局事務(wù)在執(zhí)行的時(shí)候岔乔,本地業(yè)務(wù)不可以操作全局事務(wù)中的記錄。

@ globallock + @ Transactional注解只會(huì)開啟本地事務(wù)和獲取全局鎖

一階段本地事務(wù)提交前滚躯,需要確保先拿到 全局鎖 雏门。
拿不到 全局鎖 ,不能提交本地事務(wù)掸掏。
拿 全局鎖 的嘗試被限制在一定范圍內(nèi)茁影,超出范圍將放棄,并回滾本地事務(wù)丧凤,釋放本地鎖募闲。

舉例:

兩個(gè)全局事務(wù) tx1 和 tx2,分別對(duì) a 表的 m 字段進(jìn)行更新操作愿待,m 的初始值 1000浩螺。

tx1 先開始,開啟本地事務(wù)仍侥,拿到本地鎖要出,更新操作 m = 1000 - 100 = 900。本地事務(wù)提交前农渊,先拿到該記錄的 全局鎖 患蹂,本地提交釋放本地鎖。

tx2 后開始砸紊,開啟本地事務(wù)传于,拿到本地鎖,更新操作 m = 900 - 100 = 800批糟。本地事務(wù)提交前格了,嘗試拿該記錄的 全局鎖 ,tx1 全局提交前徽鼎,該記錄的全局鎖被 tx1 持有盛末,tx2 需要重試等待 全局鎖 弹惦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市悄但,隨后出現(xiàn)的幾起案子棠隐,更是在濱河造成了極大的恐慌,老刑警劉巖檐嚣,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件助泽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嚎京,警方通過(guò)查閱死者的電腦和手機(jī)嗡贺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鞍帝,“玉大人诫睬,你說(shuō)我怎么就攤上這事∨劣浚” “怎么了摄凡?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蚓曼。 經(jīng)常有香客問(wèn)我亲澡,道長(zhǎng),這世上最難降的妖魔是什么纫版? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任床绪,我火速辦了婚禮,結(jié)果婚禮上捎琐,老公的妹妹穿的比我還像新娘会涎。我一直安慰自己裹匙,他們只是感情好瑞凑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著概页,像睡著了一般籽御。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惰匙,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天技掏,我揣著相機(jī)與錄音,去河邊找鬼项鬼。 笑死哑梳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绘盟。 我是一名探鬼主播鸠真,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼悯仙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了吠卷?” 一聲冷哼從身側(cè)響起锡垄,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎祭隔,沒想到半個(gè)月后货岭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疾渴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年千贯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搞坝。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丈牢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞄沙,到底是詐尸還是另有隱情己沛,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布距境,位于F島的核電站申尼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏垫桂。R本人自食惡果不足惜师幕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诬滩。 院中可真熱鬧霹粥,春花似錦、人聲如沸疼鸟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)空镜。三九已至浩淘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吴攒,已是汗流浹背张抄。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留洼怔,地道東北人署惯。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像镣隶,于是被迫代替她去往敵國(guó)和親极谊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子什荣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354