【深入淺出Seata原理及實(shí)戰(zhàn)】「入門基礎(chǔ)專題」探索Seata服務(wù)的AT模式下的分布式開發(fā)實(shí)戰(zhàn)指南(2)

承接上文

上一篇文章說到了Seata 為用戶提供了 AT、TCC馒索、SAGA 和 XA 事務(wù)模式名船,為用戶打造一站式的分布式解決方案渠驼。那么接下來我們將要針對(duì)于AT模式下進(jìn)行分布式事務(wù)開發(fā)的原理進(jìn)行介紹以及實(shí)戰(zhàn)。

Seata AT模式

在AT百揭、TCC、SAGA 和 XA 這四種事務(wù)模式中使用最多课锌,最方便的就是 AT 模式渺贤。與其他事務(wù)模式相比请毛,AT 模式可以應(yīng)對(duì)大多數(shù)的業(yè)務(wù)場景获印,且基本可以做到無業(yè)務(wù)入侵,開發(fā)人員能夠有更多的精力關(guān)注于業(yè)務(wù)邏輯開發(fā)玻孟。

使用AT模式的前提

任何應(yīng)用想要使用Seata的 AT 模式對(duì)分布式事務(wù)進(jìn)行控制黍翎,必須滿足以下 2 個(gè)前提:

  1. 必須使用支持本地 ACID 事務(wù)特性的關(guān)系型數(shù)據(jù)庫艳丛,例如 MySQL氮双、Oracle 等;
  2. 應(yīng)用程序必須是使用 JDBC 對(duì)數(shù)據(jù)庫進(jìn)行訪問的 JAVA 應(yīng)用送爸。

Seata安裝使用

下載地址

Seata服務(wù)進(jìn)行下載的地址:https://seata.io/zh-cn/blog/download.html袭厂,訪問之后可以看到下面的資源中球匕,可以直接進(jìn)行下載亮曹,如下圖所示秘症。

image

但是由于官方維護(hù)的稍微緩慢,所以并不是最新的版本衷佃,如果你想要下載較新的版本氏义,可以去官方的Git倉庫中進(jìn)行下載對(duì)應(yīng)的版本文件包图云。地址為:https://github.com/seata/seata/releases竣况,可以看到下面的最新版本已經(jīng)到了1.6.1了

image

我們選擇下載對(duì)應(yīng)的可執(zhí)行包即可丹泉。

image

創(chuàng)建UNDO_LOG表

SEATA AT模式需要針對(duì)業(yè)務(wù)中涉及的各個(gè)數(shù)據(jù)庫表摹恨,分別創(chuàng)建一個(gè)UNDO_LOG(回滾日志)表。不同數(shù)據(jù)庫在創(chuàng)建 UNDO_LOG 表時(shí)會(huì)略有不同睁宰,以 MySQL 為例柒傻,其 UNDO_LOG 表的創(chuàng)表語句如下:

-- 注意此處0.3.0+ 增加唯一索引 ux_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;

啟動(dòng)服務(wù)

下載服務(wù)器軟件包后诅愚,將其解壓縮劫映。主要通過腳本進(jìn)行啟動(dòng)Seata服務(wù)

image

Seata Server 目錄中包含以下子目錄:

  • bin:用于存放Seata Server可執(zhí)行命令泳赋。
  • conf:用于存放Seata Server的配置文件祖今。
  • lib:用于存放Seata Server依賴的各種 Jar 包拣技。
  • logs:用于存放Seata Server的日志膏斤。

Seata Server的執(zhí)行腳本

  • seata-server.sh:主要是為Linux和Mac系統(tǒng)準(zhǔn)備的啟動(dòng)腳本邪驮。執(zhí)行sh seata-server.sh啟動(dòng)服務(wù)毅访。
  • seata-server.bat:主要是為Windows系統(tǒng)準(zhǔn)備的啟動(dòng)腳本喻粹。執(zhí)行cmd seata-server.bat啟動(dòng)服務(wù)。

其中參數(shù)的選擇范圍如下所示

--host, -h(簡略指令)該地址向注冊(cè)中心公開守呜,其他服務(wù)可以通過該ip訪問seata-server型酥,默認(rèn): 0.0.0.0
--port, -p(簡略指令) 監(jiān)聽的端口,默認(rèn)值為8091
--storeMode, -m(簡略指令)日志存儲(chǔ)模式 : file(文件)查乒、db(數(shù)據(jù)庫)冕末,默認(rèn)為:file
--help 幫助指令

例如執(zhí)行shell腳本

sh seata-server.sh -p 8091 -h 127.0.0.1 -m file

AT 模式的工作機(jī)制

Seata的AT模式工作時(shí)大致可以分為以兩個(gè)階段,下面我們就結(jié)合一個(gè)實(shí)例來對(duì) AT 模式的工作機(jī)制進(jìn)行介紹侣颂。

整體機(jī)制

兩階段提交協(xié)議的演變:

  • 一階段:業(yè)務(wù)數(shù)據(jù)回滾日志記錄在同一個(gè)本地事務(wù)中提交档桃,釋放本地鎖和連接資源。
  • 二階段:提交異步化憔晒,非常快速地完成拒担∴谕停回滾通過一階段的回滾日志進(jìn)行反向補(bǔ)償。
AT模式一階段

Seata AT模式一階段的工作流程如下圖所示


image

業(yè)務(wù)數(shù)據(jù)和回滾日志記錄在同一個(gè)本地事務(wù)中提交从撼,釋放本地鎖和連接資源州弟。

第一子階段-獲取SQL的基本信息

Seata攔截并解析業(yè)務(wù)SQL,得到SQL 的操作類型(INSERT/UPDATE/DELETE)低零、表名(tableXXX)婆翔、判斷條件(where condition = value)等相關(guān)信息。

第二子階段-查詢并備份【執(zhí)行之前】的數(shù)據(jù)快照

根據(jù)得到的業(yè)務(wù)SQL信息掏婶,生成“前鏡像查詢語句”啃奴。

select  *  from tableXX where condition=value;

執(zhí)行“前鏡像查詢語句”,得到即將執(zhí)行操作的數(shù)據(jù)雄妥,并將其保存為“前鏡像數(shù)據(jù)(beforeImage)”最蕾。

第三子階段-執(zhí)行業(yè)務(wù)操作的SQL語句

執(zhí)行業(yè)務(wù)SQL依溯,例如(update tableXX set parameter = 'value' where condition = value;),將這條記錄的進(jìn)行修改瘟则。

第四子階段-查詢業(yè)務(wù)操作之后的數(shù)據(jù)黎炉,并且保存下來

查詢后鏡像:根據(jù)“前鏡像數(shù)據(jù)”的主鍵(id : X),生成“后鏡像查詢語句”醋拧。

select  *  from tableXX where condition=value;

執(zhí)行“后鏡像查詢語句”慷嗜,得到執(zhí)行業(yè)務(wù)操作后的數(shù)據(jù),并將其保存為“后鏡像數(shù)據(jù)(afterImage)”趁仙。

第五子階段-插入保存回滾日志記錄到undo_log表中

將前后鏡像數(shù)據(jù)和業(yè)務(wù)SQL的信息組成一條回滾日志記錄洪添,插入到 UNDO_LOG 表中垦页,示例回滾日志如下雀费。

{
    "branchId": 641789253,
    "undoItems": [{
        "afterImage": {
            "rows": [{
                "fields": [{
                    "name": "id",
                    "type": 4,
                    "value": 1
                }, {
                    "name": "name",
                    "type": 12,
                    "value": "GTS"
                }, {
                    "name": "since",
                    "type": 12,
                    "value": "2014"
                }]
            }],
            "tableName": "product"
        },
        "beforeImage": {
            "rows": [{
                "fields": [{
                    "name": "id",
                    "type": 4,
                    "value": 1
                }, {
                    "name": "name",
                    "type": 12,
                    "value": "TXC"
                }, {
                    "name": "since",
                    "type": 12,
                    "value": "2014"
                }]
            }],
            "tableName": "product"
        },
        "sqlType": "UPDATE"
    }],
    "xid": "xid:xxx"
}
提交前需要獲取申請(qǐng)本地鎖
  • 提交前,向TC注冊(cè)分支:申請(qǐng)TableXXX表中痊焊,id主鍵等于N的記錄的全局鎖 盏袄。需要確保先拿到全局鎖 。
    • 拿不到全局鎖 薄啥,不能提交本地事務(wù)辕羽。
    • 拿到全局鎖,會(huì)被限制在一定范圍內(nèi)垄惧,超出范圍將放棄刁愿,并回滾本地事務(wù),釋放本地鎖到逊。
示例說明:

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

  1. tx1先開始脑题,開啟本地事務(wù),拿到本地鎖铜靶,更新操作 m = 1000 - 100 = 900叔遂。本地事務(wù)提交前,先拿到該記錄的全局鎖 争剿,本地提交釋放本地鎖已艰。

  2. tx2后開始,開啟本地事務(wù)蚕苇,拿到本地鎖旗芬,更新操作 m = 900 - 100 = 800。本地事務(wù)提交前捆蜀,嘗試拿該記錄的全局鎖 疮丛,tx1 全局提交前幔嫂,該記錄的全局鎖被 tx1 持有,tx2需要重試等待 全局鎖 誊薄。

image
  1. tx1二階段全局提交履恩,釋放全局鎖 。tx2 拿到全局鎖提交本地事務(wù)


    image
  2. 如果tx1的二階段全局回滾呢蔫,則tx1需要重新獲取該數(shù)據(jù)的本地鎖切心,進(jìn)行反向補(bǔ)償?shù)母虏僮鳎瑢?shí)現(xiàn)分支的回滾片吊。

此時(shí)绽昏,如果tx2仍在等待該數(shù)據(jù)的全局鎖,同時(shí)持有本地鎖俏脊,則tx1的分支回滾會(huì)失敗全谤。分支的回滾會(huì)一直重試,直到tx2的全局鎖等鎖超時(shí)爷贫,放棄全局鎖并回滾本地事務(wù)釋放本地鎖认然,tx1 的分支回滾最終成功。因?yàn)檎麄€(gè)過程全局鎖在tx1結(jié)束前一直是被tx1持有的漫萄,所以不會(huì)發(fā)生臟寫的問題卷员。

數(shù)據(jù)庫隔離級(jí)別

在數(shù)據(jù)庫本地事務(wù)隔離級(jí)別,讀已提交(Read Committed)或以上的基礎(chǔ)上腾务,Seata(AT 模式)的默認(rèn)全局隔離級(jí)別是讀未提交(Read Uncommitted) 毕骡。

如果應(yīng)用在特定場景下,必需要求全局的讀已提交 岩瘦,目前Seata的方式是通過 SELECT FOR UPDATE 語句的代理未巫。

image

SELECT FOR UPDATE 語句的執(zhí)行會(huì)申請(qǐng)全局鎖 ,如果全局鎖被其他事務(wù)持有担钮,則釋放本地鎖(回滾 SELECT FOR UPDATE 語句的本地執(zhí)行)并重試橱赠。這個(gè)過程中,查詢是被 block 住的箫津,直到全局鎖拿到狭姨,即讀取的相關(guān)數(shù)據(jù)是已提交的,才返回苏遥。

出于總體性能上的考慮饼拍,Seata目前的方案并沒有對(duì)所有 SELECT 語句都進(jìn)行代理,僅針對(duì) FOR UPDATE 的 SELECT 語句田炭。

本地事務(wù)提交

業(yè)務(wù)數(shù)據(jù)的更新和前面步驟中生成的UNDO LOG一并提交师抄,將本地事務(wù)提交的結(jié)果上報(bào)給TC。

AT模式二階段-回滾操作
  1. 收到TC的分支回滾請(qǐng)求教硫,開啟一個(gè)本地事務(wù)叨吮。

  2. 通過XID和Branch ID查找到相應(yīng)的UNDO LOG 記錄辆布。

  3. 數(shù)據(jù)校驗(yàn):拿 UNDO LOG 中的后鏡與當(dāng)前數(shù)據(jù)進(jìn)行比較,如果有不同茶鉴,說明數(shù)據(jù)被當(dāng)前全局事務(wù)之外的動(dòng)作做了修改锋玲。這種情況,需要根據(jù)配置策略來做處理涵叮,詳細(xì)的說明在另外的文檔中介紹惭蹂。

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

update TableXXX set parameter = 'XXX' where condition = value;
  1. 提交本地事務(wù),并把本地事務(wù)的執(zhí)行結(jié)果(即分支事務(wù)回滾的結(jié)果)上報(bào)給 TC割粮。
AT模式二階段-提交操作
  1. 收到TC的分支提交請(qǐng)求盾碗,把請(qǐng)求放入一個(gè)異步任務(wù)的隊(duì)列中,馬上返回提交成功的結(jié)果給 TC舀瓢。

  2. 異步任務(wù)階段的分支提交請(qǐng)求將異步和批量地刪除相應(yīng) UNDO LOG 記錄廷雅。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市氢伟,隨后出現(xiàn)的幾起案子榜轿,更是在濱河造成了極大的恐慌幽歼,老刑警劉巖朵锣,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異甸私,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門葛圃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來型檀,“玉大人,你說我怎么就攤上這事弃鸦〗视酰” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵唬格,是天一觀的道長家破。 經(jīng)常有香客問我,道長购岗,這世上最難降的妖魔是什么汰聋? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮喊积,結(jié)果婚禮上烹困,老公的妹妹穿的比我還像新娘。我一直安慰自己乾吻,他們只是感情好髓梅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布拟蜻。 她就那樣靜靜地躺著,像睡著了一般枯饿。 火紅的嫁衣襯著肌膚如雪瞭郑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天鸭你,我揣著相機(jī)與錄音屈张,去河邊找鬼。 笑死袱巨,一個(gè)胖子當(dāng)著我的面吹牛阁谆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播愉老,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼场绿,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了嫉入?” 一聲冷哼從身側(cè)響起焰盗,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咒林,沒想到半個(gè)月后熬拒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垫竞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年澎粟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欢瞪。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡活烙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出遣鼓,到底是詐尸還是另有隱情啸盏,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布骑祟,位于F島的核電站回懦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏曾我。R本人自食惡果不足惜粉怕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抒巢。 院中可真熱鬧贫贝,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至客燕,卻和暖如春鸳劳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背也搓。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國打工赏廓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人傍妒。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓幔摸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親颤练。 傳聞我的和親對(duì)象是個(gè)殘疾皇子既忆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容