在轉賬業務中,有兩步,乙個是操作使用者a扣錢,乙個是操作使用者b加錢
如果在同乙個資料庫中進行,可以保證這兩步操作,要麼同時成功,要麼同時不成功。這樣就保證了轉賬的資料一致性。但是如果使用者a的資料在集群a中,使用者b在集群b中呢?因為他們不在同乙個事務中;如使用者a扣款成功,但使用者b加錢失敗了;那就坑了,資料不完整了。
類似這種問題在微服務架構會更多,因為各個服務都是獨立的模組,都是遠端呼叫,都沒法在同乙個事務中,都會遇到事務問題。上圖就是利用訊息中介軟體的方式,把扣款業務和加錢業務非同步化,扣款成功後,傳送「扣款成功訊息」到訊息中介軟體;加錢業務訂閱「扣款成功訊息」,再對使用者b加錢
系統怎麼知道給使用者b加錢呢?是訊息體裡面包含了源賬戶和目標賬戶id,以及錢數這個時候也許小夥伴們會問,應該也有問題吧:場景一:先扣款後發訊息
先扣款再傳送訊息,萬一傳送訊息失敗了,那使用者b就沒法加錢那把順序調整一下場景二:先發訊息,後扣款
扣款成功訊息傳送成功,但使用者a扣款失敗,可加錢業務訂閱到了訊息,使用者b加了錢大家應該發現了問題所在,也就是沒法保證扣款和傳送訊息,同時成功,或同時失敗;導致資料不一致。
因為上面的問題,rocketmq訊息中介軟體把訊息分為兩個階段:prepared階段和確認階段prepared階段(預備階段)
該階段主要發乙個訊息到rocketmq,但該訊息只儲存在commitlog中,但consumequeue中不可見,也就是消費端(訂閱端)無法看到此訊息。commit/rollback階段(確認階段)
該階段主要是把prepared訊息儲存到consumequeue中,即讓消費端可以看到此訊息,也就是可以消費此訊息。我們用圖來說明下:
整個流程:
1、在扣款之前,先傳送預備訊息2、傳送預備訊息成功後,執行本地扣款事務3、扣款成功後,再傳送確認訊息4、訊息端(加錢業務)可以看到確認訊息,消費此訊息,進行加錢確認訊息說明
注意:上面的確認訊息可以為commit訊息,可以被訂閱者消費;也可以是rollback訊息,即執行本地扣款事務失敗後,提交rollback訊息,即刪除那個預備訊息,訂閱者無法消費我們來分析一下異常場景:
異常1:如果傳送預備訊息失敗,下面的流程不會走下去;這個是正常的異常2:如果傳送預備訊息成功,但執行本地事務失敗;這個也沒有問題,因為此預備訊息不會被消費端訂閱到,消費端不會執行業務。異常3:如果傳送預備訊息成功,執行本地事務成功,但傳送確認訊息失敗;這個就有問題了,因為使用者a扣款成功了,但加錢業務沒有訂閱到確認訊息,無法加錢。這裡出現了資料不一致。那rocketmq是怎麼解決的呢?
rocketmq如何解決上面的問題,核心思路就是【狀態回查】,也就是rocketmq會定時遍歷commitlog中的預備訊息。
因為預備訊息最終肯定會變為commit訊息或rollback訊息,所以遍歷預備訊息去回查本地業務的執行狀態,如果發現本地業務沒有執行成功就rollback,如果執行成功就傳送commit訊息。上面的異常3,傳送預備訊息成功,本地扣款事務成功,但傳送確認訊息失敗;因為rocketmq會進行回查預備訊息,在回查後發現業務已經扣款成功了,就補發「傳送commit確認訊息」;這樣加錢業務就可以訂閱此訊息了。
這個思路其實把異常2也解決了,因為本地事務沒有執行成功,rocketmq回查業務,發現沒有執行成功,就會傳送rollback確認訊息,把訊息進行刪除。小夥伴們在回查業務中,如何判斷本地事務是否執行成功?
如果本地事務執行了很多張表,那是不是我們要把那些表都要進行判斷是否執行成功呢?這樣是不是太麻煩了,而且和業務很耦合。有沒有更好的方式呢?就是設計一張transaction表,將業務表和transaction繫結在同乙個本地事務中,如果扣款本地事務成功時,transaction中應當已經記錄該transactionid的狀態為「已完成」。當rocketmq回查時,只需要檢查對應的transactionid的狀態是否是「已完成」就好,而不用關心具體的業務資料。
分布式一致性
分布式一致性是指在分布式環境中對某個副本資料進行更新操作時,必須確保其他副本也會更新,避免不同副本資料不一致。分布式系統乙個重要的問題時解決資料複製,一是為了增加系統的可用性防止單點故障,二是提高系統可用性,通過負載聚恆,使分布在不同位置的資料副本能夠提供服務。理想狀態下,當然希望分布式系統能夠實現...
分布式一致性
分布式系統的乙個重要問題是資料的複製。對資料的複製一般有兩個原因 資料複製的主要難題是保持各個副本的一致性。即在更新乙個副本時,必須確保同時更新其他的副本,否則資料的各個副本將不再相同。一致性模型實質上是程序和資料儲存之間的乙個約定。正常情況下,乙個資料項上執行讀操作時,它期待該操作返回的是該資料在...
分布式一致性方案
首先,先說一下。老外提出了乙個快取更新套路,名為 cache aside pattern 其中就指出 不是的。假設這會有兩個請求,乙個請求a做查詢操作,乙個請求b做更新操作,那麼會有如下情形產生 快取剛好失效 請求a查詢資料庫,得乙個舊值 請求b將新值寫入資料庫 請求b刪除快取 請求a將查到的舊值寫...