分布式事務(wù)產(chǎn)生的原因
- 數(shù)據(jù)庫分庫分表
- 微服務(wù)化
- 在微服務(wù)架構(gòu)中荞雏,每個服務(wù)在用
本地事務(wù)
的時候,知道自己執(zhí)行的事務(wù)是成功還是失敗平酿,但是無法知道其他服務(wù)節(jié)點(diǎn)的事務(wù)執(zhí)行情況凤优,因此需要引入協(xié)調(diào)者TM
,負(fù)責(zé)協(xié)調(diào)參與者RM
的行為蜈彼,并最終決定這些參與者是否把事務(wù)進(jìn)行提交筑辨。
隨著微服務(wù)架構(gòu)的流行,讓分布式事務(wù)問題日益突出幸逆, 那么常見的分布式事務(wù)解決方案有哪些呢棍辕? 如何理解最終一致性和它的事務(wù)補(bǔ)償機(jī)制呢?
剛性事務(wù) - 強(qiáng)一致性
如上圖还绘,這是個標(biāo)準(zhǔn)的全局事務(wù)楚昭,事務(wù)管理器
控制著全局事務(wù),管理事務(wù)的生命周期拍顷,并通過XA協(xié)議與資源管理器
協(xié)調(diào)資源抚太;資源管理器負(fù)責(zé)控制和管理實(shí)際的資源 (這里的資源管理器,可以是一個DBMS昔案,或者消息服務(wù)管理系統(tǒng))
兩階段提交
它是XA用于在全局事務(wù)中協(xié)調(diào)多個資源的機(jī)制尿贫,常用于事務(wù)管理器
和資源管理器
之間,解決一致性問題踏揣,分兩階段:
- 提交事務(wù)請求
- 執(zhí)行事務(wù)請求
2PC的問題
- 效率低庆亡,與本地事務(wù)相比,XA協(xié)議的系統(tǒng)開銷比較大(數(shù)據(jù)被鎖定的時間跨度整個事務(wù)捞稿,直到全局事務(wù)的結(jié)束)又谋,只有支持XA協(xié)議的資源才能參與分布式事務(wù)钝尸。
- 2PC是反可伸縮模式的,在事務(wù)處理過程中搂根,參與者需要一直持有資源直到整個事務(wù)的結(jié)束珍促,這樣當(dāng)業(yè)務(wù)規(guī)模越來越大的情況下,它的局限性就越明顯剩愧。
- 數(shù)據(jù)不一致猪叙,在2pc中的第二階段時,當(dāng)TM向RM發(fā)送提交請求之后仁卷,發(fā)生局部的網(wǎng)絡(luò)異逞妫或者在發(fā)送提交請求過程中TM發(fā)生故障, 這會導(dǎo)致只有一部分RM收到了提交請求锦积,然后沒有收到提交請求的RM不會執(zhí)行事務(wù)的提交芒帕,于是整個分布式系統(tǒng)便會出現(xiàn)數(shù)據(jù)不一致。
- 單點(diǎn)故障丰介, 由于TM的重要性背蟆,一旦發(fā)生故障,整個事務(wù)失效
3PC的改進(jìn)
增加了超時機(jī)制
哮幢, 主要解決單點(diǎn)故障問題带膀,并減少資源鎖定時間,一旦RM無法及時收到來至TM的信息之后橙垢,它會默認(rèn)執(zhí)行Commit操作垛叨, 而不會一直持有事務(wù)資源并處于阻塞狀態(tài)。但是這種機(jī)制同樣會導(dǎo)致數(shù)據(jù)不一致的問題柜某,由于網(wǎng)絡(luò)的原因嗽元,TM發(fā)送的回滾動作,沒有被RM及時的收到喂击,那么RM等待超時后就執(zhí)行了提交操作剂癌,這樣就和收到回滾操作并執(zhí)行的RM之間存在了數(shù)據(jù)不一致的情況。
柔性事務(wù) - 最終一致性
在2008年惭等,eBay公布了基于BASE
準(zhǔn)則的最終一致性解決方案珍手,它主要采用了消息隊列來輔助實(shí)現(xiàn)事務(wù)控制流程办铡,其核心通過消息隊列的方式來異步執(zhí)行分布式處理的任務(wù)辞做,如果事務(wù)失敗,則可以發(fā)起人工重試的糾正流程(比如對賬系統(tǒng)寡具,對處于dead letter queue
的問題進(jìn)行處理)
消息發(fā)送一致性
微服務(wù)架構(gòu)下秤茅,需要通過網(wǎng)絡(luò)進(jìn)行通信,就自然引入了數(shù)據(jù)傳輸?shù)牟淮_定性童叠,也就是CAP原理中的P-分區(qū)容錯框喳,而這里的消息發(fā)送一致性
是可靠消息的保證课幕。
生成消息的業(yè)務(wù)動作與消息發(fā)送的一致(e.g: 如果業(yè)務(wù)操作成功,那么由這個業(yè)務(wù)操作所產(chǎn)生的消息一定會成功投遞出去五垮,否則就丟失消息)
如上圖乍惊,保證消息發(fā)送一致性的一般流程如下:
- Producer先把消息發(fā)送給消息中間件服務(wù),消息的狀態(tài)標(biāo)記為
待確認(rèn)
放仗,這個狀態(tài)并不會被Consumer消費(fèi)润绎,對于長期待確認(rèn)
的消息,消息中間件會調(diào)用Producer的查詢接口诞挨,查看最新狀態(tài)莉撇,根據(jù)結(jié)果決定是否刪除消息。 - Producer執(zhí)行完業(yè)務(wù)操作后惶傻,向消息中間件服務(wù)棍郎,發(fā)送確認(rèn)消息
- 這時消息的狀態(tài)會被更改為
待發(fā)送(可發(fā)送)
- Consumer監(jiān)聽并接收待發(fā)送狀態(tài)的消息,執(zhí)行業(yè)務(wù)處理
- Consumer業(yè)務(wù)處理后银室,向消息中間件服務(wù)發(fā)送
ACK
涂佃,確認(rèn)消息已經(jīng)收到(消息中間件服務(wù)將從隊列中刪除該消息)
消息的ACK確認(rèn)流程中,任何一個環(huán)節(jié)都可能會出問題蜈敢!
對未ACK
的消息巡李,采用按規(guī)則重新投遞的方式進(jìn)行處理(很多MQ都提供at least once的投遞,持久化和重試機(jī)制)扶认,一般還會設(shè)置重發(fā)
的次數(shù)侨拦, 超過次數(shù)的消息會進(jìn)入dead letter queue
,等待人工干預(yù)或者延后定時處理辐宾。
業(yè)務(wù)接口的冪等性
消息的重復(fù)發(fā)送會導(dǎo)致業(yè)務(wù)接口出現(xiàn)重復(fù)調(diào)用的問題狱从,主要原因就是消息沒有及時收到ACK確認(rèn)導(dǎo)致的, 那如何實(shí)現(xiàn)冪等性設(shè)計呢叠纹?
在實(shí)際的業(yè)務(wù)場景中季研, 業(yè)務(wù)接口的冪等性設(shè)計,常結(jié)合查詢操作一起使用誉察,
比如根據(jù)唯一標(biāo)識
查詢消息是否被處理過与涡, 或者根據(jù)消費(fèi)日志表,來維護(hù)消息消費(fèi)的記錄持偏。
保證最終一致性的模式
- 可查詢模式驼卖,任何一個服務(wù)操作都提供一個可查詢接口,用來向外部輸出操作執(zhí)行的狀態(tài)鸿秆,下游Consumer可以通過接口得知服務(wù)操作執(zhí)行的狀態(tài)酌畜,然后根據(jù)不同的狀態(tài)做不同的處理操作(執(zhí)行或者取消), 該模式對業(yè)務(wù)接口有一定侵入性卿叽。
-
補(bǔ)償模式桥胞, 有了查詢模式恳守,我們能夠知道操作的具體狀態(tài),如果處于不正常狀態(tài)贩虾,我們可以
修正
操作中出現(xiàn)的問題催烘,或許是重新執(zhí)行,或許取消已經(jīng)完成的操作缎罢,通過修復(fù)是的整個分布式系統(tǒng)達(dá)到最終一致颗圣。 - 最大努力通知模式, 在調(diào)用支付寶交易接口或微信支付接口時屁使,一般會在回調(diào)頁面和接口里在岂,解密參數(shù),然后調(diào)用系統(tǒng)中更新交易狀態(tài)相關(guān)的服務(wù)蛮寂,將訂單更新為付款成功蔽午。同時,只有當(dāng)回調(diào)頁面中輸出了success字樣或者標(biāo)識業(yè)務(wù)處理成功相應(yīng)狀態(tài)碼時酬蹋,支付寶才會停止回調(diào)請求及老。否則,支付寶會每間隔一段時間后范抓,再向客戶方發(fā)起回調(diào)請求骄恶,直到輸出成功標(biāo)識為止。