分布式事務(wù)方案 - 最終一致性

在分布式時(shí)代,分庫(kù)分表是很常見(jiàn)的,微服務(wù)系統(tǒng)中,各個(gè)系統(tǒng)通常使用獨(dú)立的數(shù)據(jù)庫(kù),所以,事務(wù)很難靠數(shù)據(jù)庫(kù)本身保證,只能靠業(yè)務(wù)系統(tǒng)來(lái)解決。

例如支付寶中的余額寶、花唄,具體不清楚,但猜測(cè)應(yīng)該就是2個(gè)服務(wù),不是同一個(gè)數(shù)據(jù)庫(kù),我們還花唄的時(shí)候通常都是從余額寶中扣除的,這就是分布式事務(wù),一個(gè)系統(tǒng)中扣減錢(qián),一個(gè)系統(tǒng)中增加錢(qián)。

下面我們分析下最終一致性的實(shí)現(xiàn)方案,最終一致性通常都是使用消息中間件來(lái)實(shí)現(xiàn)的,系統(tǒng)結(jié)構(gòu)如下:

image-20210630215541712.png

解釋下上圖的流程:用戶(hù)向系統(tǒng)A發(fā)起轉(zhuǎn)賬請(qǐng)求,A先在自己的數(shù)據(jù)庫(kù)中扣錢(qián),然后通過(guò)消息中間件告訴B應(yīng)該加錢(qián),B收到后在自己的數(shù)據(jù)庫(kù)中加錢(qián)。

這里有個(gè)關(guān)鍵問(wèn)題,A更新數(shù)據(jù)庫(kù)和給消息中間件發(fā)消息是2個(gè)操作,如下兩個(gè)場(chǎng)景怎么處理:

  • 先更新數(shù)據(jù)庫(kù),成功了,但發(fā)送消息失敗了,重發(fā)多次還是失敗
  • 先發(fā)消息,成功了,但數(shù)據(jù)庫(kù)更新失敗,消息撤不回來(lái)了

就是因?yàn)檫@2個(gè)操作不是原子性的,先執(zhí)行哪一步都會(huì)有問(wèn)題。

那我們就嘗試著把更新數(shù)據(jù)庫(kù)和給消息中間件發(fā)消息放到一個(gè)事務(wù)中可以嗎?這樣不就能實(shí)現(xiàn)原子性操作了嗎?

實(shí)際上這樣時(shí)存在問(wèn)題的,例如:

  • 如果消息發(fā)送失敗,具體問(wèn)題出在哪兒?是消息中間件根本就沒(méi)收到消息,還是收到消息后response時(shí)出錯(cuò)了?如果是根本沒(méi)收到還好一點(diǎn),如果是收到了但響應(yīng)失敗就麻煩了,導(dǎo)致A數(shù)據(jù)庫(kù)回滾,沒(méi)有扣錢(qián),但B收到消息了,加錢(qián)了。
  • 如果發(fā)消息時(shí)網(wǎng)絡(luò)延遲很高怎么辦,數(shù)據(jù)庫(kù)事務(wù)一直被拖著,性能差,風(fēng)險(xiǎn)高。

故而放入一個(gè)事務(wù)中這種方法是不可取的。

為了保證原子性,可以變通一下,添加一個(gè)消息表,A不直接往消息中間件中發(fā)消息,而是把消息寫(xiě)入消息表,然后通過(guò)一個(gè)后臺(tái)程序不斷的把消息寫(xiě)入消息中間件。

image-20210630221415581.png

這個(gè)后臺(tái)程序源源不斷的把消息表中的消息發(fā)到消息中間件,如果失敗就重試,可以保證:

  • 消息不會(huì)丟失
  • 順序不亂

但此時(shí)會(huì)有消息重復(fù)的情況,因?yàn)橄l(fā)送失敗可能是寫(xiě)入失敗,也可能是寫(xiě)入成功但響應(yīng)失敗,所以消息可能會(huì)重復(fù)發(fā)送,這個(gè)問(wèn)題需要系統(tǒng)B來(lái)處理。

系統(tǒng)B需要考慮2個(gè)問(wèn)題:

  • 消息丟失
  • B從消息中間件中拿到消息,還沒(méi)處理完就宕機(jī)了,這條消息怎么辦?

此時(shí)就需要通過(guò)ACK機(jī)制處理,消費(fèi)成功的發(fā)送ACK,對(duì)于沒(méi)有ACK的消息,消息中間件會(huì)再次推送。

但ACK機(jī)制也存在消息重復(fù)的情況,比如B已經(jīng)處理完一條消息,發(fā)ACK時(shí)失敗了,那么這條消息就還會(huì)被推過(guò)來(lái)。

或者像上面說(shuō)到的后臺(tái)程序發(fā)消息時(shí)可能重復(fù)。

對(duì)于重復(fù)消息問(wèn)題,可以加一個(gè)判重表,記錄處理成功的消息,每次收到消息時(shí),先通過(guò)判重表判斷一下,如果重復(fù)了就不處理,實(shí)現(xiàn)冪等性

最終,整體的結(jié)構(gòu)就變?yōu)槿缦滤荆?/p>

image-20210630221350893.png

以上就是通過(guò)最終一致性解決分布式事務(wù)問(wèn)題的基本思路,A 保證消息不丟,B 保證消息不漏、冪等。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容