分佈式事務方案 - 最終一致性

在分佈式時代,分庫分表是很常見的,微服務系統中,各個系統一般使用獨立的數據庫,因此,事務很難靠數據庫自己保證,只能靠業務系統來解決。java

例如支付寶中的餘額寶、花唄,具體不清楚,但猜想應該就是2個服務,不是同一個數據庫,咱們還花唄的時候一般都是從餘額寶中扣除的,這就是分佈式事務,一個系統中扣減錢,一個系統中增長錢。數據庫

下面咱們分析下最終一致性的實現方案,最終一致性一般都是使用消息中間件來實現的,系統結構以下:微信

在這裏插入圖片描述
用戶向系統A發起轉帳請求,A先在本身的數據庫中扣錢,而後經過消息中間件告訴B應該加錢,B收到後在本身的數據庫中加錢。網絡

這裏有個關鍵問題,A更新數據庫和給消息中間件發消息是2個操做,以下兩個場景怎麼處理:分佈式

先更新數據庫,成功了,但發送消息失敗了,重發屢次仍是失敗微服務

先發消息,成功了,但數據庫更新失敗,消息撤不回來了性能

都是由於這2個操做不是原子的,發作誰都有問題。code

那看下這樣作是否能夠,就是把更新數據庫和給消息中間件發消息放到一個事務中,這樣不就原子了嗎?中間件

有問題,例如:blog

若是消息發送失敗,具體問題出在哪兒?是消息中間件根本就沒收到消息,仍是收到消息後response時出錯了?若是是根本沒收到還好一點,若是是收到了但響應失敗就麻煩了,致使A數據庫回滾,沒有扣錢,但B收到消息了,加錢了。

若是發消息時網絡延遲很高怎麼辦,數據庫事務一直被拖着,性能差,風險高。

因此,放入一個事務中這種方法是不可取的。

爲了保證原子性,能夠變通一下,添加一個消息表,A不直接往消息中間件中發消息,而是把消息寫入消息表,而後經過一個後臺程序不斷的把消息寫入消息中間件。

在這裏插入圖片描述

這個後臺程序源源不斷的把消息表中的消息發到消息中間件,若是失敗就重試,能夠保證:

消息不會丟失

順序不亂

但會有消息重複的狀況,由於消息發送失敗多是寫入失敗,也多是寫入成功但響應失敗,因此消息可能會重複,這個問題須要系統B來處理。

系統B須要考慮2個問題:

消息丟失

B從消息中間件中拿到消息,還沒處理完就宕機了,這條消息怎麼辦?

須要經過ACK機制處理,消費成功的發送ACK,對於沒有ACK的消息,消息中間件會再次推送。

消息重複

ACK機制也存在消息重複的狀況,好比B已經處理完一條消息,發ACK時失敗了,那麼這條消息就還會被推過來。

還有就是上面說的後臺程序發消息時可能重複。

對於重複消息問題,能夠加一個判重表,記錄處理成功的消息,每次收到消息時,先經過判重表判斷一下,若是重複了就不處理,實現冪等性。

這樣,總體結構就變爲:

在這裏插入圖片描述

以上就是經過最終一致性解決分佈式事務問題的基本思路,A 保證消息不丟,B 保證消息不漏、冪等。

對分佈式事務有興趣、或有疑問的,能夠加我微信itsoku交流

請關注公衆號javacode2018,免費領取年薪40萬的資料,更多好文及時推送給您

相關文章
相關標籤/搜索