這篇文章將介紹分布式事務(wù)中的多種實(shí)現(xiàn)方案缴饭,及各種分布式事務(wù)方案的實(shí)現(xiàn)原理、事務(wù)執(zhí)行過(guò)程骆莹、優(yōu)缺點(diǎn)颗搂,讀完這篇文章相信你會(huì)對(duì)2PC、3PC幕垦、TCC丢氢、MQ事務(wù)消息有個(gè)詳細(xì)的了解
分布式事務(wù)的處理方法有哪些?
XA協(xié)議:基于分布式事務(wù)協(xié)議先改,主要由事務(wù)管理器和本地資源管理器組成疚察,事務(wù)管理器是一個(gè)全局調(diào)度者,負(fù)責(zé)本地資源管理器統(tǒng)一的提交或回滾事務(wù)仇奶。mysql貌嫡、oracle均已支持XA協(xié)議
2PC(兩階段提交)
基本流程:
-
Prepare預(yù)備階段
:預(yù)執(zhí)行需要執(zhí)行的sql,但不提交事務(wù) -
Commit提交階段
:提交事務(wù)
不足:
- 數(shù)據(jù)不一致:在事務(wù)管理器向所有服務(wù)發(fā)送提交事務(wù)Commit階段時(shí),某些參與者可能發(fā)生網(wǎng)絡(luò)抖動(dòng)岛抄,無(wú)法正常接收到Commit請(qǐng)求别惦,從而導(dǎo)致每個(gè)參與者的數(shù)據(jù)不一致
- 超時(shí)導(dǎo)致同步阻塞:當(dāng)有一個(gè)參與者出現(xiàn)通信超時(shí),其余所有參與者將一直阻塞無(wú)法釋放資源
- 單點(diǎn)故障風(fēng)險(xiǎn):如圖可知夫椭,資源管理器統(tǒng)一協(xié)調(diào)所有參與者掸掸,一旦資源管理器出現(xiàn)故障,則參與者無(wú)法完成Commit操作蹭秋,會(huì)一直處于阻塞狀態(tài)扰付。盡管資源管理器會(huì)重新選舉,當(dāng)還是無(wú)法解決之前遺留的阻塞問(wèn)題仁讨。
- 性能問(wèn)題:所有參與者在事務(wù)提交階段處于同步阻塞狀態(tài)悯周,占用系統(tǒng)資源,容易導(dǎo)致性能瓶頸
3PC(三階段提交)
基本流程:
-
CanCommit
:協(xié)調(diào)者向所有參與者發(fā)送CanCommit命令陪竿,禽翼,詢問(wèn)是否可以執(zhí)行事務(wù)提交操作。如果全部響應(yīng)YES則進(jìn)入下一個(gè)階段 -
PreCommit
:預(yù)提交事務(wù)操作族跛,詢問(wèn)是否可以進(jìn)行事務(wù)的預(yù)提交操作闰挡,參與者接收到PreCommit請(qǐng)求后,如參與者成功的執(zhí)行了事務(wù)操作礁哄,則返回Yes響應(yīng)长酗,進(jìn)入最終commit階段。一旦參與者中有向協(xié)調(diào)者發(fā)送了No響應(yīng)桐绒,或因網(wǎng)絡(luò)造成超時(shí)夺脾,協(xié)調(diào)者沒(méi)有接到參與者的響應(yīng),協(xié)調(diào)者向所有參與者發(fā)送abort請(qǐng)求茉继,參與者接受abort命令執(zhí)行事務(wù)的中斷咧叭。 -
DoCommit
:前兩個(gè)階段都返回YES響應(yīng)后,協(xié)調(diào)者向參與者發(fā)送DoCommit正式提交事務(wù)命令烁竭,如果沒(méi)有接收到ACK響應(yīng)菲茬,則向其它參與者發(fā)送abort命令,執(zhí)行事務(wù)中斷
相對(duì)于2PC的改進(jìn):
- <mark style="box-sizing: border-box; outline: 0px; background-color: rgb(248, 248, 64); color: rgb(0, 0, 0); overflow-wrap: break-word;">在協(xié)調(diào)者與參與者加入了超時(shí)機(jī)制</mark>派撕,當(dāng)在一定時(shí)間內(nèi)未收到協(xié)調(diào)者的commit請(qǐng)求婉弹,會(huì)自動(dòng)提交事務(wù),不會(huì)一致阻塞等待
- 3PC將2PC的Prepare準(zhǔn)備階段拆分為 2 個(gè)階段终吼,插入了一個(gè) ==PreCommit ==階段镀赌,解決原先在2PC中,由于協(xié)調(diào)者發(fā)生故障而導(dǎo)致參與者無(wú)法知曉是否commit或abort的狀態(tài)而產(chǎn)生的相當(dāng)長(zhǎng)的阻塞問(wèn)題得以解決
- 有了自動(dòng)提交事務(wù)际跪,一旦發(fā)生單點(diǎn)故障商佛,事務(wù)也可以自動(dòng)提交
不足:
- 在發(fā)送abort命令的時(shí)候蛙粘,如果因?yàn)榫W(wǎng)絡(luò)原因部分參與者沒(méi)有接收到請(qǐng)求,還是會(huì)導(dǎo)致數(shù)據(jù)不一致性問(wèn)題
TCC(事務(wù)補(bǔ)償)
TCC也是實(shí)現(xiàn)分布式事務(wù)的一種方案威彰,不過(guò)它是屬于應(yīng)用層面的出牧,非基于XA協(xié)議,需要我們編寫業(yè)務(wù)代碼來(lái)實(shí)現(xiàn)類似于2PC的命令功能
核心思想:
<mark style="box-sizing: border-box; outline: 0px; background-color: rgb(248, 248, 64); color: rgb(0, 0, 0); overflow-wrap: break-word;">對(duì)于每一個(gè)操作都有其對(duì)應(yīng)的確認(rèn)(Confirm)和補(bǔ)償(Cancel)方法歇盼,且它們是冪等性的</mark>
基本流程:
-
Try
:通過(guò)Try操作來(lái)檢查舔痕、預(yù)留需要的庫(kù)存,比如需要2臺(tái)iphone12并進(jìn)行凍結(jié) -
Confirm
:真正執(zhí)行業(yè)務(wù)操作豹缀,在之前預(yù)留的資源基礎(chǔ)上完成購(gòu)買和創(chuàng)建訂單 -
Cancel
:在Try階段預(yù)留2臺(tái)iphone12失敗伯复,則取消所有業(yè)務(wù)資源的預(yù)留(也就是恢復(fù)try之前)
優(yōu)點(diǎn):
- 性能提升:依據(jù)業(yè)務(wù)來(lái)控制資源鎖的粒度,不會(huì)控制整個(gè)資源
- 數(shù)據(jù)最終一致性:基于Confirm和Cancel的冪等性邢笙,能夠保證事務(wù)完成或取消
- 可靠性:解決了XA協(xié)議中事務(wù)管理器單點(diǎn)故障問(wèn)題啸如,直接由業(yè)務(wù)活動(dòng)發(fā)起并控制整個(gè)業(yè)務(wù)活動(dòng),業(yè)務(wù)活動(dòng)管理器也變成了多點(diǎn)(集群)
不足:
7. 代碼侵入性強(qiáng):之前也說(shuō)需要在業(yè)務(wù)層面實(shí)現(xiàn)這三個(gè)命令氮惯,實(shí)際就是需要實(shí)現(xiàn)三個(gè)接口
8. 開發(fā)成本高:因?yàn)樾枰约簩?shí)現(xiàn)三個(gè)階段的業(yè)務(wù)代碼叮雳,開發(fā)量很大;且如果要保證數(shù)據(jù)一致性妇汗,需要自己實(shí)現(xiàn)冪等性
RocketMQ事務(wù)消息(最終一致性)
基本流程:
- 事務(wù)主動(dòng)方向消息集群發(fā)送消息帘不,但這個(gè)消息不能被消費(fèi)
- 事務(wù)主動(dòng)方執(zhí)行本地事務(wù)A,執(zhí)行成功后根據(jù)消息地址去修改消息狀態(tài)為commit或rollback杨箭,如果是commit則會(huì)被事務(wù)被動(dòng)方消費(fèi)寞焙,否則將刪除消息
- 事務(wù)被動(dòng)方讀取消息,然后執(zhí)行本地事務(wù)B
- 事務(wù)被動(dòng)方將事務(wù)B執(zhí)行結(jié)果返回到MQ Server
- 事務(wù)主動(dòng)方讀取接收方事務(wù)處理結(jié)果
異常情況1:如果事務(wù)主動(dòng)方發(fā)送commit or rollback消息失敗互婿,未到達(dá)消息集群
- 消息集群(MQ Server)會(huì)發(fā)起消息回查
- 事務(wù)主動(dòng)方收到回查消息后捣郊,會(huì)檢查本地事務(wù)的執(zhí)行結(jié)果
- 根據(jù)本地事務(wù)的執(zhí)行結(jié)果重新發(fā)送commit or rollback消息
- MQ Server根據(jù)接收到的消息(commit or rollback)判斷消息是否可消費(fèi)或直接刪除
異常情況2:接收方消費(fèi)失敗或消費(fèi)超時(shí)
一直<mark style="box-sizing: border-box; outline: 0px; background-color: rgb(248, 248, 64); color: rgb(0, 0, 0); overflow-wrap: break-word;">重試消費(fèi)</mark>,直到事務(wù)被動(dòng)方消費(fèi)消息成功慈参,整個(gè)過(guò)程可能會(huì)導(dǎo)致重復(fù)消費(fèi)問(wèn)題呛牲,所以業(yè)務(wù)邏輯需要保證冪等性
異常情況3:消息已消費(fèi),但接收方業(yè)務(wù)處理失敗
通過(guò)MQ Server通知發(fā)送方進(jìn)行補(bǔ)償或事務(wù)回滾
優(yōu)點(diǎn):
- 系統(tǒng)解耦:消息之間獨(dú)立存儲(chǔ)懂牧,系統(tǒng)之間消息完成事務(wù)
- 復(fù)雜度低侈净,實(shí)現(xiàn)簡(jiǎn)單
缺點(diǎn):
- 一次消息需要發(fā)送兩次請(qǐng)求(half消息+commit or rollback)
- 業(yè)務(wù)中需要實(shí)現(xiàn)消息狀態(tài)回查接口
Spring中已經(jīng)有了事務(wù),還需要使用事務(wù)消息嗎僧凤?
如果是在Spring框架下,可以將發(fā)送消息的邏輯綁定到本地事務(wù)中元扔,發(fā)消息失敗就拋出異常躯保,回滾事務(wù),以此來(lái)保證本地事務(wù)與發(fā)送消息的原子性