基于Saga的分布式事務(wù)調(diào)度落地

一浩村、背景

隨著微服務(wù)架構(gòu)的興起露戒,越來越多的公司都對自身的業(yè)務(wù)架構(gòu)進(jìn)行了微服務(wù)化。在微服務(wù)架構(gòu)中白嘁,隨著服務(wù)的逐漸拆分坑鱼,數(shù)據(jù)庫的私有化已成為業(yè)界不成文的規(guī)定。因此伴隨著微服務(wù)拆分所帶來的數(shù)據(jù)一致性的問題也愈發(fā)嚴(yán)重絮缅,如何解決該問題成為微服務(wù)架構(gòu)落地過程中一個非常重要的問題鲁沥。由此我們引出分布式事務(wù)這一概念呼股,用來解決上述背景帶來的問題。在介紹分布式事務(wù)之前先讓我們回顧一下什么是事務(wù)画恰。

二彭谁、事務(wù)

事務(wù)是數(shù)據(jù)庫操作的最小工作單元,是作為單個邏輯工作單元執(zhí)行的一系列操作允扇;這些操作作為一個整體一起向系統(tǒng)提交缠局,要么都執(zhí)行、要么都不執(zhí)行蔼两;事務(wù)具有ACID四大屬性甩鳄。

A(Atomic):原子性,構(gòu)成事務(wù)的所有操作额划,要么都執(zhí)行完成妙啃,要么全部不執(zhí)行,不可能出現(xiàn)部分成功部分失敗的情況俊戳。

C(Consistency):一致性揖赴,在事務(wù)執(zhí)行前后,數(shù)據(jù)庫的一致性約束沒有被破壞抑胎。比如:數(shù)據(jù)庫約束賬戶余額必須大于0燥滑,所以設(shè)置為無符號數(shù),在此約束下阿逃,A只有100元铭拧,但要轉(zhuǎn)出200元,此時數(shù)據(jù)庫會保持對約束的一致性恃锉,觸發(fā)執(zhí)行回滾搀菩。

I(Isolation):隔離性,數(shù)據(jù)庫中的事務(wù)一般都是并發(fā)的破托,隔離性是指并發(fā)的兩個事務(wù)的執(zhí)行互不干擾肪跋,一個事務(wù)不能看到其他事務(wù)的運行過程的中間狀態(tài)。通過配置事務(wù)隔離級別可以比避免臟讀土砂、重復(fù)讀問題州既。

D(Durability):持久性,事務(wù)完成之后萝映,該事務(wù)對數(shù)據(jù)的更改會持久到數(shù)據(jù)庫吴叶,且不會被回滾。

了解完了事務(wù)的基本概念序臂,接著讓我們看看什么是分布式事務(wù)蚌卤。

三、分布式事務(wù)

在分布式系統(tǒng)中,一個應(yīng)用系統(tǒng)拆分為獨立部署的多個服務(wù)造寝,因此需要服務(wù)與服務(wù)之間遠(yuǎn)程協(xié)作才能完成事務(wù)操作,這種分布式系統(tǒng)環(huán)境下由不同的服務(wù)之間通過網(wǎng)絡(luò)遠(yuǎn)程協(xié)作完成的事務(wù)稱為分布式事務(wù)吭练。

從架構(gòu)角度出發(fā)诫龙,分布式事務(wù)基本涉及到兩大類。

第一類:一個事務(wù)請求只涉及單體服務(wù)鲫咽,但是會操作多張數(shù)據(jù)庫表签赃,多個數(shù)據(jù)庫表操作完成才表示最終完成。

第二類:一個事務(wù)涉及多個服務(wù)分尸,同時每個服務(wù)可能連接著一個或者多個數(shù)據(jù)庫锦聊,需要協(xié)同多個獨立的服務(wù)訪問多個數(shù)據(jù)存儲最終才能完成。

我們常見的分布式事務(wù)來保證數(shù)據(jù)的一致性的方法分為兩類:強一致性箩绍、最終一致性孔庭。

采用強一致性的分布式事務(wù)的方案:通常采用兩段式提交協(xié)議2PC、三段式提交協(xié)議3PC材蛛。在微服務(wù)架構(gòu)中圆到,該種方式不太適合,原因如下:

由于微服務(wù)間無法直接進(jìn)行數(shù)據(jù)訪問卑吭,微服務(wù)間互相調(diào)用通常通過RPC或Http API進(jìn)行芽淡,所以已經(jīng)無法使用TM統(tǒng)一管理微服務(wù)的RM

不同的微服務(wù)使用的數(shù)據(jù)源類型可能完全不同,如果微服務(wù)使用了NoSQL之類不原生支持事務(wù)的數(shù)據(jù)庫豆赏,業(yè)務(wù)的事務(wù)很難實現(xiàn)

即使微服務(wù)使用的數(shù)據(jù)源都支持事務(wù)挣菲,那么如果使用一個大事務(wù)將許多微服務(wù)的事務(wù)管理起來,這個大事務(wù)維持的時間掷邦,將比本地事務(wù)長幾個數(shù)量級白胀。如此長時間的事務(wù)及跨服務(wù)的事務(wù),將為產(chǎn)生很多鎖及數(shù)據(jù)不可用耙饰,嚴(yán)重影響系統(tǒng)性能

因此我們一般采用最終一致性來保證分布式系統(tǒng)的一致性纹笼。

常見的最終一致性的分布式事務(wù)解決方案有:事件通知模式(本地異步事件服務(wù)模式、外部事件服務(wù)模式苟跪、MQ事務(wù)消息模式廷痘、最大努力通知模式)、事務(wù)補償模式(Saga件已、TCC)笋额。我們通過調(diào)研上述解決方案總結(jié)出了以下特性:

image.png

下面我們通過一個業(yè)務(wù)場景來了解一下什么是分布式事務(wù),并且我們創(chuàng)新行業(yè)是用什么方案來解決數(shù)據(jù)一致性問題的篷扩。

四兄猩、業(yè)務(wù)場景

假設(shè)有一個積分簽到系統(tǒng),里面有一個簽到兌換積分從而兌換物品的功能場景。

image.png

我們要做的事情如下:

  • 用戶簽到成功枢冤、增加用戶積分

  • 用戶創(chuàng)建兌換物品訂單鸠姨,訂單狀態(tài)為已支付

  • 扣除用戶積分

  • 扣減物品庫存

  • 創(chuàng)建物流出庫單

針對以上的業(yè)務(wù)場景,我們應(yīng)該如何實現(xiàn)分布式事務(wù)來滿足業(yè)務(wù)需要淹真。下面主要講事務(wù)補償模式來實現(xiàn)分布式事務(wù)讶迁。

4.1 TCC 模式

TCC是將整體業(yè)務(wù)邏輯的每一個事務(wù)提交分成了Try,Confirm核蘸,Cancel三個操作巍糯。

  • Try:完成業(yè)務(wù)的準(zhǔn)備工作

  • Confirm:完成業(yè)務(wù)的提交工作

  • Cancel:完成業(yè)務(wù)的回滾工作

針對上述業(yè)務(wù)場景,按照業(yè)務(wù)背景要做的事情客扎,實現(xiàn)一個TCC的分布式事務(wù)祟峦。

如果要實現(xiàn)一個TCC的分布式事務(wù),首先要做的是了解業(yè)務(wù)的主流程以及各個接口提供的業(yè)務(wù)含義徙鱼,不直接完成這個業(yè)務(wù)操作宅楞,而是完成一個Try(預(yù)處理)操作。

例如:給用戶添加積分疆偿,我們不直接添加積分咱筛,先預(yù)處理添加積分「斯剩扣物品庫存我們也不直接扣庫存迅箩,先凍結(jié)將扣掉的庫存。具體如下圖

image.png

如果Try的邏輯都成功处铛,TCC開始執(zhí)行業(yè)務(wù)的Confirm操作饲趋,完成整個事務(wù)流程。添加用戶積分扣庫存等操作撤蟆。如果Try的邏輯部分成功奕塑,有部分有問題,那么開始執(zhí)行Cancel操作家肯,撤銷之前執(zhí)行的所有操作龄砰。

總體對于TCC模式來說,要做一個分布式事務(wù)讨衣,業(yè)務(wù)中的一個接口需要完成3個邏輯的改造换棚,Try-Confirm-Cancel。

  • 服務(wù)調(diào)用鏈路依次執(zhí)行Try邏輯

  • 如果都正常的話反镇,執(zhí)行Confirm邏輯固蚤,完成整個業(yè)務(wù)流程

  • 如果部分服務(wù)的Try邏輯有問題,會執(zhí)行Cancel邏輯歹茶,撤銷之前執(zhí)行的所有操作

TCC模式對于業(yè)務(wù)的侵入性比較強夕玩,流程比較繁瑣你弦。各個業(yè)務(wù)側(cè)都需要支持升級。對于我們創(chuàng)新行業(yè)來說燎孟,成本有點大禽作,我們選擇了另一種模式來實現(xiàn)分布式事務(wù)——Saga模式。

4.2 Saga模式

Saga是一種純業(yè)務(wù)補償模式揩页,其設(shè)計理念為领迈,業(yè)務(wù)在調(diào)用的時候正常提交,當(dāng)一個服務(wù)失敗的時候碍沐,所有其依賴的上游服務(wù)都進(jìn)行業(yè)務(wù)補償操作。

Saga的基本概念:

  • saga:長事務(wù)衷蜓,long live transaction

  • 每個本地事務(wù)有對應(yīng)的補償事務(wù)

  • 執(zhí)行情況

  • 正常:T1 -> T2 -> T3 -> … -> Tn

  • 異常:T1 -> T2 -> T3(異常)-> C3 -> C2 -> C1

Saga兩種恢復(fù)策略:

  • backward recovery累提,向后恢復(fù),補償所有已完成的事務(wù)(回滾操作)

  • forward recovery磁浇,向前恢復(fù)斋陪,重試失敗的事務(wù),假設(shè)每個子事務(wù)最終都會成功(重試操作)

Saga事務(wù)的優(yōu)缺點:

  • 優(yōu)點:模型比TCC更簡單置吓,只需業(yè)務(wù)方提供事務(wù)執(zhí)行接口transaction无虚、事務(wù)取消補償接口cancel

  • 缺點:直接執(zhí)行事務(wù)執(zhí)行接口transaction,可能有副作用(無論是否回滾衍锚,都會執(zhí)行事務(wù)接口的邏輯友题,舉例:A賬號向B賬號轉(zhuǎn)賬,T1事務(wù)對A用戶扣款戴质,T2事務(wù)對B用戶加款度宦,T1執(zhí)行成功,同時產(chǎn)生了一條扣款記錄告匠,T2執(zhí)行失敗需要回滾T2和T1戈抄,在這個過程中的副作用是A賬號能感知到金額變化和扣款記錄)

針對上述業(yè)務(wù)背景,我們對于業(yè)務(wù)側(cè)只需要支持事務(wù)提交的接口( T )和失敗補償?shù)慕涌冢?C )即可后专。具體流程如下圖:

image.png

對于Saga事務(wù)來說只有完成跟未完成兩種狀態(tài)划鸽。無論是事務(wù)全部執(zhí)行成功,還是全部補償成功都視為完成狀態(tài)戚哎。出現(xiàn)異常導(dǎo)致流程中斷為未完成狀態(tài)裸诽。我們針對于業(yè)務(wù)提交的流程的Http Code狀態(tài)來區(qū)分是執(zhí)行向前恢復(fù)(重試),還是向后補償(回滾)建瘫。對于沒有補償 C 的業(yè)務(wù)崭捍,我們將采取向前恢復(fù),直到成功啰脚。對于異常情況殷蛇,使用離線補償?shù)姆绞綄ξ赐瓿傻腟aga事務(wù)進(jìn)行重做实夹,如長時間無法完成將觸發(fā)報警,人工處理粒梦。

我們行創(chuàng)基于上述saga模型研發(fā)了Saga的事務(wù)協(xié)調(diào)器亮航,具體執(zhí)行流程如下:

image.png

業(yè)務(wù)方使用需要實現(xiàn)對應(yīng)事務(wù)的執(zhí)行方法和補償方法,采用上報分布式事務(wù)的方式進(jìn)行操作匀们,事務(wù)上報的數(shù)據(jù)屬性簡介:

  • Name:本次流程的名稱

  • OID:請求流程ID缴淋,必須唯一

  • Process:每個子流程的屬性簡介(類型為list,按照順序執(zhí)行)

  • Transaction:執(zhí)行事務(wù)的流程

  • Call:服務(wù)調(diào)用的方式泄朴,HTTP調(diào)用時傳GET重抖、POST等

  • ServiceName:服務(wù)名稱

  • ServiceMethod:調(diào)用服務(wù)的方法名稱,HTTP傳請求的URL

  • Body:POST body祖灰,string類型

  • Query:Get Query钟沛,map[string]interfase{}

  • oid:訂單ID, 必傳局扶,必須唯一恨统,用于冪等性校驗等

  • Compensate:執(zhí)行失敗的補償流程

  • Call:服務(wù)調(diào)用的方式,HTTP調(diào)用時傳GET三妈、POST等

  • ServiceName:服務(wù)名稱

  • ServiceMethod:調(diào)用服務(wù)的方法名稱畜埋,HTTP傳請求的URL

  • Body:POST body,string類型

  • Query:Get Query畴蒲,map[string]interfase{}

  • oid:訂單ID悠鞍, 必傳,必須唯一模燥,用于冪等性校驗等

業(yè)務(wù)方按上述規(guī)則上報數(shù)據(jù)狞玛,該事務(wù)會最終保證數(shù)據(jù)一致性,要么全部成功涧窒,要么都失敗回滾心肪。

我們創(chuàng)新行業(yè)采用Saga模型來實現(xiàn)分布式事務(wù),來解決日常微服務(wù)拆分帶來的數(shù)據(jù)一致性的問題纠吴,滿足了我們?nèi)粘5漠a(chǎn)品功能的需要硬鞍,解決了棘手的問題。

五戴已、總結(jié)

針對分布式事務(wù)的解決方案都有各自的特點固该,沒有一個最優(yōu)的方案,需要結(jié)合實際的應(yīng)用場景選擇合適的模式糖儡。

  • 2PC 和 3PC 是一種強一致性事務(wù)伐坏,不過還是有數(shù)據(jù)不一致,阻塞等風(fēng)險握联,而且只能用在數(shù)據(jù)庫層面桦沉。

  • Saga每瞒、TCC是一種補償性事務(wù)的思想,對業(yè)務(wù)入侵較大纯露,需要業(yè)務(wù)方實現(xiàn)對應(yīng)的方法剿骨。

  • 本地消息、事務(wù)消息和最大努力通知其實都是最終一致性事務(wù)埠褪,因此適用于一些對時間不敏感的業(yè)務(wù)浓利。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钞速,隨后出現(xiàn)的幾起案子贷掖,更是在濱河造成了極大的恐慌,老刑警劉巖渴语,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羽资,死亡現(xiàn)場離奇詭異,居然都是意外死亡遵班,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門潮改,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狭郑,“玉大人,你說我怎么就攤上這事汇在『踩” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵糕殉,是天一觀的道長亩鬼。 經(jīng)常有香客問我,道長阿蝶,這世上最難降的妖魔是什么雳锋? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮羡洁,結(jié)果婚禮上玷过,老公的妹妹穿的比我還像新娘。我一直安慰自己筑煮,他們只是感情好辛蚊,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著真仲,像睡著了一般袋马。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秸应,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天虑凛,我揣著相機(jī)與錄音碑宴,去河邊找鬼。 笑死卧檐,一個胖子當(dāng)著我的面吹牛墓懂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播霉囚,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼捕仔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了盈罐?” 一聲冷哼從身側(cè)響起榜跌,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盅粪,沒想到半個月后钓葫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡票顾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年础浮,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奠骄。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡豆同,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出含鳞,到底是詐尸還是另有隱情影锈,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布蝉绷,位于F島的核電站鸭廷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏熔吗。R本人自食惡果不足惜辆床,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桅狠。 院中可真熱鬧佛吓,春花似錦、人聲如沸垂攘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽晒他。三九已至吱型,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陨仅,已是汗流浹背津滞。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工铝侵, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人触徐。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓咪鲜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親撞鹉。 傳聞我的和親對象是個殘疾皇子疟丙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

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