假設(shè):消息服務(wù)不丟消息
場(chǎng)景 服務(wù)A 服務(wù)B 服務(wù)C 消息服務(wù)Q
偽代碼
服務(wù)A中
transaction{
A本地事務(wù)
B.callB();
C.callC();
A本地事務(wù)
}
利用消息服務(wù)來(lái)實(shí)現(xiàn)分布式事務(wù)
原理 當(dāng)服務(wù)A執(zhí)行事務(wù)時(shí),所有指定遠(yuǎn)程調(diào)用會(huì)被轉(zhuǎn)換為發(fā)送一條調(diào)用消息到消息服務(wù),當(dāng)B和C接收到消息時(shí),立即執(zhí)行消息指定的方法,并在提交前發(fā)送回復(fù)消息給A(攜帶有返回值)并且等待接收提交或者回滾消息,服務(wù)A執(zhí)行完方法也在提交前等待B和C的回復(fù),當(dāng)B和C的回復(fù)都為sucess時(shí)發(fā)送提交消息給B和C,然后自己提交,否則回滾。B和C接到提交消息后,提交,否則回滾。
異常情況一:在發(fā)送調(diào)用B的消息時(shí)失敗
服務(wù)A事務(wù)直接回滾
異常情況二:在發(fā)送調(diào)用C的消息時(shí)失敗
服務(wù)A事務(wù)直接回滾,并發(fā)送回滾消息到指定隊(duì)列(此兩步操作由Q的事務(wù)消息保證原子性)
異常情況三:服務(wù)A提交和回滾失敗
由于服務(wù)A提交和回滾操作和發(fā)送提交或者回滾消息在一個(gè)事務(wù)內(nèi),所以放在一起討論,
由于此部分由消息中間件保證原子性,固提交或者回滾失敗,不會(huì)有提交或者回滾消息到達(dá)消息中間件,B和C等待一段時(shí)間后自動(dòng)回滾
異常情況四:B在發(fā)送回復(fù)消息時(shí)失敗
A在等待指定時(shí)間后沒有收到B的回復(fù),進(jìn)行回滾操作并發(fā)送回滾消息到指定隊(duì)列,C在收到回滾消息后回滾,B在等待指定時(shí)間后沒有收到A的提交消息回滾
異常情況五:C在發(fā)送回復(fù)消息時(shí)失敗
同異常情況四
異常情況六:B提交失敗或者C提交失敗
B或C中調(diào)用消息和提交消息均不消費(fèi),會(huì)進(jìn)行重試
異常情況七:B或者C回滾失敗
同異常情況六
異常情況八:B或者C邏輯出現(xiàn)異常導(dǎo)致失敗
B或者C直接回滾,并且發(fā)送失敗回復(fù)
停機(jī)啟動(dòng)恢復(fù)處理
由于異常導(dǎo)致的死機(jī),然后重啟后的邏輯
一、只接收到調(diào)用消息,執(zhí)行,然后等待固定時(shí)間后回滾。
二、按照順序接收到調(diào)用消息和提交消息,執(zhí)行然后提交
三、先接收到提交消息后接收到調(diào)用消息,一樣,執(zhí)行然后提交
四、接收到調(diào)用和回滾消息,同上
從上可以推導(dǎo)出,利用消息系統(tǒng)做分布式事務(wù)的兩個(gè)特性
強(qiáng)調(diào)一下假設(shè):消息服務(wù)不丟消息
一、在網(wǎng)絡(luò)暢通所有服務(wù)高可用的情況下,可以做到數(shù)據(jù)的強(qiáng)一致性
二、在網(wǎng)絡(luò)和服務(wù)可能存在故障的情況下,可以做到數(shù)據(jù)的最終一致性
關(guān)于數(shù)據(jù)在最終一致性情況下的查詢問題
1.最好的解決方案是不管,更新后查詢數(shù)據(jù)查到舊的數(shù)據(jù)就讓它查到舊的數(shù)據(jù)
2.可以利用緩存,自己寫邏輯實(shí)現(xiàn),還未提交的數(shù)據(jù)緩存下來(lái),查詢時(shí)先查詢緩存