分散式事務系列 - 解決跨庫轉賬問題
本文內容
- 什麼是分散式事務
- 分散式事務中的難點
- 常見的解決方案
- 講解通過可靠訊息來解決分散式事務
什麼是分散式事務?
有這樣一個需求:
小明有兩個賬戶,分別位於A、B兩個資料庫中,小明需要將A中的資金轉到B中。
我們如何實現?
按照下面的方式實現看看有沒有問題。
- 連線資料庫A,獲取connA連線
- connA開啟事務
- A庫資金減少100
- 連線庫B,獲取connB連線
- connB開啟事務
- B庫資金增加100
- connA.commit()
- connB.commit()
上面操作,正常情況是沒有問題。
考慮如下情況:
第7步執行成功之後,網路出問題了,第8步會提交失敗,此時的結果是:A庫資金減少了100,B庫資金卻沒有增加;這是一個網路問題導致了我們業務失敗了,網路因素是程式不可控的一些因素,還有其他的比如執行到7之後,系統突然斷電了,也會出現同樣的結果。造成了資料錯誤,對業務影響也是比較大的。
分散式事務可以這麼理解:一個業務操作中,會包含很多子業務的,每個子業務都是獨立的事務,我們需要考慮的是如何保證這些子業務都成功,或者都失敗。
分散式事務中的難點
- 分散式事務中,分支可能是各種各樣的,可能存在各種異常情況導致有些成功有些卻失敗了,這些情況需要我們程式能夠處理,保證所有的分支要麼都成功、要麼都失敗,不能出現部分成功而部分失敗的情況。
- 分散式事務中,很難保證多個分支同時成功。每個分支可能都是提供遠端介面進行呼叫,之間存在網路故障的問題,前面的分支呼叫成功了,但是其他分支由於網路等不可控的因素而呼叫不成功,此時資料是很難做到同時一致性的。
- 實時一致性難以保證。那麼我們可以做到最終一致性也是可以的。
什麼是最終一致性?
就拿上面的轉賬來說,A庫的資金減少了,由於網路問題,操作B庫的connB連線斷開了,導致B庫資金沒有增加;網路問題是可以恢復了,如果網路恢復了,系統能夠給B中資金加上,這樣最終資料也是正確的;這中間有段時間AB庫的資金是不一致的(A庫減少了100,B庫應該增加100卻沒有增加,資料是不一致的),但是最終某個時間點資料變為一致了。能夠將不一致的時間降到最低是系統需要考慮的問題。
分散式事務中,我們可以接受資料在某個時間段之內不一致,但是資料最終在某個時間點是一致的。
常見解決方案
- 可靠訊息模式
- TCC模式實現
分散式事務系列中主要講這2種方案,這兩種方案基本上可以解決大多數常見的分散式事務的問題,所以咱們必須把這兩種方式拿下。
下面我們介紹一下使用可靠訊息如何實現?
可靠訊息模式實現轉賬操作
兩個微服務
服務A:用於操作A庫中的賬戶
服務B:用於操作B庫中的賬戶
兩個服務都是連結獨立的資料庫,依靠資料庫提供的功能,能夠保證各自的事務。
對於使用者來說過程如下:
- 呼叫服務A,扣款100
- 傳送扣款成功的訊息到訊息服務
- 返回使用者轉賬已受理
接著
- 服務B,拉取到轉賬訊息
- B庫中給賬戶+100
- 呼叫訊息服務將訊息刪除
- 服務B消費的過程中,比如出現網路、機器重啟等原因,導致消費失敗,等機器恢復之後,可以再次消費這條訊息,重試多次最終會成功
上面整個轉賬過程中有幾點我們需要考慮一下:
- 如何確保A服務中扣款成功之後,訊息一定能夠傳送成功;如果訊息傳送失敗而丟失了,後面的業務將沒法進行。這塊涉及如何傳送可靠訊息,之前訊息系列的文章有介紹,大家可以看一下:聊聊業務系統中投遞訊息到mq的幾種方式
- 我們的服務一般都是叢集的方式,訊息消費的時候,可能會出現一條訊息併發消費的情況,併發情況發生的時候,如何確保消費只能夠被消費成功一次。如果一條轉賬訊息被成功消費兩次,最終B賬戶中將增加200,導致業務出錯。這塊可以參考如何保證訊息消費的冪等性,這塊之前也有講過,大家也可以看一下:探討一下實現冪等性的幾種方式
依靠訊息模式實現分散式事物,比較適合消費者一定會處理成功的場景。比如使用者註冊傳送郵件、傳送簡訊、送積分等。
總結
- 本文主要介紹了什麼是分散式事務、其中的一些難點
- 常見的使用最多的解決方案:非同步訊息處理分散式事物、tcc模式
- tcc模式我們在後面的文章中介紹,目前在我們自己的系統中實現了通用的tcc,已經上線執行,執行也比較穩定
- 對分散式事務有興趣、或有疑問的,可以加我微信itsoku交流
- 請關注公眾號javacode2018,免費領取年薪40萬的資料,更多好文及時推送給您