我們在說到事務(wù)的時候搬味,總會以轉(zhuǎn)賬作為經(jīng)典案例:用戶下單買東西境氢,一次買賣過程會扣件庫存,生成訂單碰纬,扣減賬戶余額萍聊;在這樣的情況下,如果要保證數(shù)據(jù)業(yè)務(wù)的成功悦析,必須引入事務(wù)寿桨。不再贅述。
在事務(wù)案例里面强戴,我們的項目結(jié)構(gòu)是這樣的亭螟,Storage、Order骑歹、Account是一個服務(wù)里的三個功能模塊预烙,他們共同面對一個DB,這時候陵刹,啟用本地事務(wù)默伍,就可以實現(xiàn)三個操作的共同成功和共同失敗。
然而衰琐,我們知道也糊,如果庫存、訂單羡宙、賬戶分別在不同的服務(wù)當(dāng)中狸剃,每個服務(wù)對應(yīng)自己的DB,那么本地事務(wù)就沒有辦法去限制和判斷其他操作是否一致性完成狗热。這就需要引入分布式事務(wù)钞馁。
分布式系統(tǒng)的三大原則:CAP
我們介紹解決方案之前,我們先介紹分布式系統(tǒng)的三大原則匿刮,也就是總會被提到的CAP定理:一致性(Consistency)僧凰、可用性(Availability)、分區(qū)容錯性(Partition tolerance)熟丸,分別解釋一下:
一致性:我們希望分布式系統(tǒng)中各個節(jié)點的數(shù)據(jù)能保證一致训措,這里的“一致”,對于主從數(shù)據(jù)庫來說是指主庫和從庫要保證數(shù)據(jù)一致。還是還有一層意思绩鸣,就是分布式系統(tǒng)任何時刻數(shù)據(jù)都是最新狀態(tài)怀大。比如我買了東西,接下來order和account返回的就是最新的狀態(tài)呀闻,我能從數(shù)據(jù)庫中直接查到化借;再比如我們剛對數(shù)據(jù)庫insert了一條數(shù)據(jù),立馬select捡多,我們希望從數(shù)據(jù)庫中返回的就是剛剛insert的數(shù)據(jù)蓖康。
如果我們要做到以上所說的,我們需要master向slave同步數(shù)據(jù)后局服,slave同步數(shù)據(jù)并鎖表(假設(shè)因為網(wǎng)絡(luò)原因同步需要一些時間)钓瞭,不對外開放讀的狀態(tài),直到slave數(shù)據(jù)修改成功后淫奔,解鎖。
可用性:與一致性不同堤结,所謂可用唆迁,就是每次訪問數(shù)據(jù)時都能夠得到數(shù)據(jù),不能返回錯誤和超時竞穷,這一點看起來就和保證一致性的時候同步有些沖突唐责,因為我們?yōu)榱艘恢滦缘面i表,可能就會導(dǎo)致延時瘾带。
分區(qū)容錯:分區(qū)容錯是我們使用分布式鼠哥,特別是主從復(fù)制時候的意義所在,它指的是其中一個結(jié)點掛了看政,不能使整個數(shù)據(jù)庫集群收到影響朴恳,其他服務(wù)還是可以正常運(yùn)行。
看了以上三個原則的特點允蚣,我們可以了解到于颖,CAP不能夠共存,如果需要每次返回都是最新數(shù)據(jù)嚷兔,那么就可能存在系統(tǒng)延時森渐,但是這又違反了可用性。但無論如何冒晰,分區(qū)容錯是必須保證的同衣,集群不能因為某一個結(jié)點的宕機(jī)而整個垮掉。那么所有的分布式解決方案壶运,也就是基于滿足AP或者CP來展開設(shè)計的耐齐。
還是基于上面的案例,我們來設(shè)計一個分布式事務(wù)解決方案:
拿Storage和Order舉例,既然業(yè)務(wù)上分成了兩個服務(wù)蚪缀,如果他們在各自的服務(wù)里面執(zhí)行數(shù)據(jù)操作后秫逝,告訴某一個中心操作結(jié)果,如果各自的事務(wù)提交都成功询枚,則整體成功违帆,如果其中有一個事務(wù)失敗,則一起回滾金蜀,這樣一來不就可以控制分布式事務(wù)了嗎刷后。
從上圖我們可以看到,全局的事務(wù)可以通過一個專門的服務(wù)——Transaction Manager(TM)進(jìn)行管理渊抄,它會去統(tǒng)計所有相關(guān)子事務(wù)的執(zhí)行情況尝胆,如果全部提交成功,對應(yīng)的全局事務(wù)正常結(jié)束就可以了(因為各個子事務(wù)已經(jīng)完成了提交任務(wù))护桦,如果其中有一個事務(wù)出現(xiàn)了問題含衔,我們可以根據(jù)每個子事務(wù)上的undo log進(jìn)行回滾,數(shù)據(jù)狀態(tài)修復(fù)二庵。
這其實就是Seata的實現(xiàn)原理:
在一次分布式事務(wù)中贪染,發(fā)起全局事務(wù)的服務(wù)會向Seata服務(wù)注冊一個全局事務(wù),這個全局事務(wù)會給各個子事務(wù)進(jìn)行關(guān)聯(lián):
與我們之前自己臆想的分布式事務(wù)有點出入的是催享,Seata還定義了一個事務(wù)調(diào)度服務(wù):Transaction Coordinator(TC)它用來執(zhí)行TM的指令杭隙。
- 發(fā)起全局事務(wù)的微服務(wù)會啟動一個全局事務(wù)的實例(TM),TM會告訴TC進(jìn)程“我要開啟全局事務(wù)了”因妙,這時候痰憎,TC會返回一個XID給該微服務(wù)。
- 得到XID后攀涵,該微服務(wù)上的資源管理器(Resource Manager)將子事務(wù)注冊到TC上铣耘,TC將該事務(wù)納入全局事務(wù)管理。
- 微服務(wù)開始執(zhí)行自己的本地事務(wù)汁果,比如新建一個order表數(shù)據(jù)涡拘。
- 隨著代碼邏輯的執(zhí)行,現(xiàn)在需要遠(yuǎn)程調(diào)用庫存微服務(wù)据德,去扣減庫存鳄乏,這時候這個全局的XID會一并傳給庫存服務(wù)上的TM,庫存上的MC就會在本地事務(wù)開啟之前向TC進(jìn)行子事務(wù)的注冊棘利,這樣庫存事務(wù)也被納入全局事務(wù)管理橱野。
- 庫存事務(wù)執(zhí)行完畢后,返回到訂單微服務(wù)善玫,這個時候水援,如果訂單事務(wù)也執(zhí)行完成,則由TM(TM存在于發(fā)起全局事務(wù)的服務(wù)中)告訴TC各個子事務(wù)的執(zhí)行情況,將提交或回滾的決議給到TC蜗元。
- TC根據(jù)全局事務(wù)-分支事務(wù)的映射關(guān)系執(zhí)行TM傳過來的決議或渤。