分布式事务之最终一致的Mq实现
問題的起源
分布式系統(tǒng)的特性
對(duì)分布式系統(tǒng)有過研究的讀者,可能聽說(shuō)過“CAP定律”、“Base理論”等,非常巧的是,化學(xué)理論中ACID是酸、Base恰好是堿。這里我們不對(duì)這些概念做過多的解釋,有興趣的讀者可以查看相關(guān)參考資料。
這里針對(duì)一致性我們做個(gè)簡(jiǎn)單的科普:
分布式事務(wù)有強(qiáng)一致,弱一致,和最終一致性這三種:
強(qiáng)一致
當(dāng)更新操作完成之后,任何多個(gè)后續(xù)進(jìn)程或者線程的訪問都會(huì)返回最新的更新過的值。這種是對(duì)用戶最友好的,就是用戶上一次寫什么,下一次就保證能讀到什么。根據(jù) CAP 理論,這種實(shí)現(xiàn)需要犧牲可用性。
弱一致
系統(tǒng)并不保證續(xù)進(jìn)程或者線程的訪問都會(huì)返回最新的更新過的值。系統(tǒng)在數(shù)據(jù)寫入成功之后,不承諾立即可以讀到最新寫入的值,也不會(huì)具體的承諾多久之后可以讀到。
最終一致
弱一致性的特定形式。系統(tǒng)保證在沒有后續(xù)更新的前提下,系統(tǒng)最終返回上一次更新操作的值。在沒有故障發(fā)生的前提下,不一致窗口的時(shí)間主要受通信延遲,系統(tǒng)負(fù)載和復(fù)制副本的個(gè)數(shù)影響。DNS 是一個(gè)典型的最終一致性系統(tǒng)
在分布式系統(tǒng)中,同時(shí)滿足“CAP定律”中的“一致性”、“可用性”和“分區(qū)容錯(cuò)性”三者是幾乎不可能的。在互聯(lián)網(wǎng)領(lǐng)域的絕大多數(shù)的場(chǎng)景,都需要犧牲強(qiáng)一致性來(lái)?yè)Q取系統(tǒng)的高可用性,系統(tǒng)往往只需要保證“最終一致性”,只要這個(gè)最終時(shí)間是在用戶可以接受的范圍內(nèi)即可,這時(shí)候我們只需要用短暫的數(shù)據(jù)不一致就可以達(dá)到我們想要效果。
實(shí)例描述
比如有訂單,庫(kù)存兩個(gè)數(shù)據(jù),一個(gè)下單過程簡(jiǎn)化為,加一個(gè)訂單,減一個(gè)庫(kù)存。 而訂單和庫(kù)存是獨(dú)立的服務(wù),那怎么保證數(shù)據(jù)一致性。
這時(shí)候我們需要思考一下,怎么保證兩個(gè)遠(yuǎn)程調(diào)用“同時(shí)成功”,數(shù)據(jù)一致?
請(qǐng)大家先注意一點(diǎn)遠(yuǎn)程調(diào)用最郁悶的地方就是,結(jié)果有3種,成功、失敗和超時(shí)。 超時(shí)的話,成功失敗都有可能。
一般的解決方案,大多數(shù)的做法是借助mq來(lái)做最終一致。
如何實(shí)現(xiàn)最終一致
實(shí)例分析
我們是怎么利用Mq來(lái)達(dá)到最終一致的呢?下面讓我們來(lái)一起進(jìn)行詳細(xì)的分析:
訂單業(yè)務(wù)分析
首先,拿我們上面提到的訂單業(yè)務(wù)舉例:
- 在我們進(jìn)行加訂單的過程中同時(shí)插入logA(這個(gè)過程是可以做本地事務(wù)的)
- 然后可以異步讀取logA,發(fā)mqA
- B端接收mqA,同時(shí)減少庫(kù)存,B這里需要做冪等(避免因?yàn)橹貜?fù)消息造成的業(yè)務(wù)錯(cuò)亂)
復(fù)雜的混合異步業(yè)務(wù)調(diào)用
那么我們通過上面的分析可能聯(lián)想到這樣的問題?
本地先執(zhí)行事務(wù),執(zhí)行成功了就發(fā)個(gè)消息過去,消費(fèi)端拿到消息執(zhí)行自己的事務(wù)
比如a,b,c a異步調(diào)用b,c, 如果b失敗了,或者b成功,或者b超時(shí),那么怎么用mq讓他們最終一致呢?b失敗就失敗了,b成功之后給c發(fā)一個(gè)消息,b和c對(duì)a來(lái)講都是異步的,且他們都是同時(shí)進(jìn)行的話,而且需要a,b,c同時(shí)成功的情況,那么這種情況用mq怎么做
其實(shí)做法還是參照于本地事務(wù)的概念的。
- 第一種情況:假設(shè)a,b,c三者都正常執(zhí)行,那整個(gè)業(yè)務(wù)正常結(jié)束
- 第二種情況:假設(shè)b超時(shí),那么需要a給b重發(fā)消息(記得b服務(wù)要做冪等),如果出現(xiàn)重發(fā)失敗的話,需要看情況,是終端服務(wù),還是繼續(xù)重發(fā),甚至人為干預(yù)(所有的規(guī)則制定都需要根據(jù)業(yè)務(wù)規(guī)則來(lái)定)
- 第三種情況:假設(shè)a,b,c三者之中的一個(gè)失敗了,失敗的服務(wù)利用MQ給其他的服務(wù)發(fā)送消息,其他的服務(wù)接收消息,查詢本地事務(wù)記錄日志,如果本地也失敗,刪除收到的消息(表示消息消費(fèi)成功),如果本地成功的話,則需要調(diào)用補(bǔ)償接口進(jìn)行補(bǔ)償(需要每個(gè)服務(wù)都提供業(yè)務(wù)補(bǔ)償接口)。
注意事項(xiàng)
mq這里有個(gè)坑,通常只適用于只允許第一個(gè)操作失敗的場(chǎng)景,也就是第一個(gè)成功之后必須保證后面的操作在業(yè)務(wù)上沒障礙,不然后面失敗了前面不好回滾,只允許系統(tǒng)異常的失敗,不允許業(yè)務(wù)上的失敗,通常業(yè)務(wù)上失敗一次后面基本上也不太可能成功了,要是因?yàn)榫W(wǎng)絡(luò)或宕機(jī)引起的失敗可以通過重試解決,如果業(yè)務(wù)異常,那就只能發(fā)消息給a和c讓他們做補(bǔ)償了吧?通常是通過第三方進(jìn)行補(bǔ)償,ABC提供補(bǔ)償接口,設(shè)計(jì)范式里通常不允許消費(fèi)下游業(yè)務(wù)失敗
上面的話我們?cè)撛趺蠢斫饽?#xff0c;舉個(gè)例子吧:
比如A給B轉(zhuǎn)賬,A先自己扣錢,然后發(fā)了個(gè)消息,B這邊如果在這之前銷戶了,那重試多少次也沒用,只能人工干預(yù)
阿里在分布式事務(wù)采用的解決方式
阿里部分業(yè)務(wù)是用Mq實(shí)現(xiàn)了最終一致性,也有一部分業(yè)務(wù)用了tcc事務(wù),但是tcc事務(wù)用的比較少,因?yàn)闀?huì)侵染業(yè)務(wù),開發(fā)成本比較高,如果體量不大的話直接用jta或mq支持事務(wù)就好,其實(shí)在分布式事務(wù)這一塊還有一種最大努力型,也比較無(wú)腦的一種方式。
聲明
以上觀點(diǎn)均為個(gè)人總結(jié),不代表完全正確。
作者:jsondream
鏈接:http://www.jianshu.com/p/716d3ec567c0
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的分布式事务之最终一致的Mq实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聊聊分布式事务
- 下一篇: JVM内存管理–GC算法精解(五分钟让你