面试必备的分布式事物方案
四月初,去面試了本市的一家之前在做辦公室無(wú)人貨架的公司,雖然他們現(xiàn)在在面臨著轉(zhuǎn)型,但是對(duì)于我這種想從傳統(tǒng)企業(yè)往互聯(lián)網(wǎng)行業(yè)走的孩子來(lái)說(shuō),還是比較有吸引力的。
在面試過(guò)程中就提到了分布式事物問(wèn)題。我又一次在沒(méi)有好好整理的問(wèn)題上吃了虧,記錄一下,還是長(zhǎng)記性 !!!
先看面試過(guò)程
面試官先是在紙上先畫(huà)了這樣一張圖:
讓我看這張圖按照上面的流程走,有沒(méi)有什么問(wèn)題?面試官并沒(méi)有直接說(shuō)出來(lái)這里面會(huì)有分布式事物的問(wèn)題,而是讓我來(lái)告訴他,這就是面試套路呀。
我回答了這中間可能存在分布式事物的問(wèn)題,當(dāng)步驟2在調(diào)用 B 系統(tǒng)時(shí),可能存在B 系統(tǒng)處理完成后,在響應(yīng)的時(shí)候超時(shí),導(dǎo)致 A 系統(tǒng)誤認(rèn)為 B 處理失敗了,從而導(dǎo)致A 系統(tǒng)回滾,跟 B 系統(tǒng)存在數(shù)據(jù)不一致的情況。
ok ,我回答到這里,應(yīng)該回答了面試官的第一層意思,至少我有這種意識(shí),他點(diǎn)了點(diǎn)頭。
接著,他繼續(xù)問(wèn):“那你有什么好的解決方式嗎?”
此時(shí)我腦子里面只有兩階段提交的大概流程圖的印象,然后巴卡巴拉的跟他說(shuō)了一番,什么中間來(lái)個(gè)協(xié)調(diào)者呀,先預(yù)提交什么的,如果有失敗,就?rollback,如果 ok,再真正的提交事物,就是網(wǎng)上這些大神們說(shuō)的這些理論。
然后面試官就繼續(xù)問(wèn):那A 在調(diào)用 B 的這條線斷了,你們代碼具體是怎么處理的呢 ?怎么來(lái)做到 rollback 的呢 ?說(shuō)說(shuō)你代碼怎么寫(xiě)的。
此時(shí),我懵了。
最后結(jié)果,大家肯定也能猜到,涼涼。
什么是事務(wù)
這里我們說(shuō)的事務(wù)一般是指?數(shù)據(jù)庫(kù)事務(wù),簡(jiǎn)稱?事務(wù),是數(shù)據(jù)庫(kù)管理系統(tǒng)執(zhí)行過(guò)程中的一個(gè)邏輯單位,由一個(gè)有限的數(shù)據(jù)庫(kù)操作序列構(gòu)成。維基百科中這么說(shuō)的。
用轉(zhuǎn)賬的例子來(lái)說(shuō),A 賬戶要給 B 賬戶轉(zhuǎn) 100塊,這中間至少包含了兩個(gè)操作:
1.A 賬戶 減 100 塊
2.B 賬戶 加 100 塊
在支持事務(wù)的數(shù)據(jù)庫(kù)管理系統(tǒng)來(lái)說(shuō),就是得確保上面兩個(gè)操作(整個(gè)“事務(wù)”)都能完成,不能存在,A 的100塊扣了,然后B的賬戶又沒(méi)加上去的情況。
數(shù)據(jù)庫(kù)事務(wù)包含了四個(gè)特性,分別是:
?原子性(Atomicity):事務(wù)作為一個(gè)整體被執(zhí)行,包含在其中的對(duì)數(shù)據(jù)庫(kù)的操作要么全部被執(zhí)行,要么都不執(zhí)行。對(duì)于轉(zhuǎn)賬來(lái)說(shuō),A賬戶扣錢(qián),B 賬戶加錢(qián),要么同時(shí)成功,要么同時(shí)失敗。
?一致性(Consistency):事務(wù)應(yīng)確保數(shù)據(jù)庫(kù)的狀態(tài)從一個(gè)一致?tīng)顟B(tài)轉(zhuǎn)變?yōu)榱硪粋€(gè)一致?tīng)顟B(tài)。一致?tīng)顟B(tài)的含義是數(shù)據(jù)庫(kù)中的數(shù)據(jù)應(yīng)滿足完整性約束
?隔離性(Isolation):多個(gè)事務(wù)并發(fā)執(zhí)行時(shí),一個(gè)事務(wù)的執(zhí)行不應(yīng)影響其他事務(wù)的執(zhí)行。其他賬戶在轉(zhuǎn)賬的時(shí)候,不能影響到上面的 A 跟 B 之前的交易。
?持久性(Durability):已被提交的事務(wù)對(duì)數(shù)據(jù)庫(kù)的修改應(yīng)該永久保存在數(shù)據(jù)庫(kù)中。
什么是分布式事物
我們知道,上面的轉(zhuǎn)賬 我們是在一個(gè)數(shù)據(jù)庫(kù)中的事務(wù)操作。我們可以使用一些框架 比如 Spring 的事務(wù)管理器來(lái)給我們統(tǒng)一搞定。
但是如果我們系統(tǒng)中出現(xiàn)垮庫(kù)操作,比如一個(gè)操作中,我需要操作多個(gè)庫(kù),或者說(shuō)這個(gè)操作會(huì)垮應(yīng)用之前的調(diào)用,那么Spring 的事務(wù)管理機(jī)制就對(duì)這種場(chǎng)景沒(méi)有辦法了。
就像上面面試題中出現(xiàn)的問(wèn)題一樣,在系統(tǒng) A 的步驟 2 在遠(yuǎn)程調(diào)用 B 的時(shí)候,由于網(wǎng)絡(luò)超時(shí),導(dǎo)致B 沒(méi)有正常響應(yīng),但是A 這邊調(diào)用失敗,進(jìn)行了回滾,而 B 又提交了事物。此時(shí)就可能會(huì)導(dǎo)致數(shù)據(jù)不一致的情況,參生分布式事物的問(wèn)題。
分布式事物的存在,就是解決數(shù)據(jù)不一致的情況。
為什么我們要保證一致性
CAP 理論
分布式系統(tǒng)中有這么一個(gè)廣為流傳的理論:CAP 定理
這個(gè)定理呀,起源于加州大學(xué)柏克萊分校(University of California, Berkeley)的計(jì)算機(jī)科學(xué)家埃里克·布魯爾在 2000年的分布式計(jì)算原理研討會(huì)(PODC)上提出的一個(gè)猜想。后來(lái)在2002年,麻省理工學(xué)院(MIT)的賽斯·吉爾伯特和南希·林奇發(fā)表了布魯爾猜想的證明,使之成為一個(gè)定理。【摘自維基百科】
他說(shuō)呀,對(duì)于一個(gè)分布式計(jì)算系統(tǒng)來(lái)說(shuō),不可能同時(shí)滿足以下三點(diǎn):
?一致性(Consistency)
?可用性(Availability)
?分區(qū)容錯(cuò)性(Partition tolerance)
而一個(gè)分布式系統(tǒng)最多只能滿足其中的兩項(xiàng)。
那么,上面的三點(diǎn)分別是什么玩意兒?為什么又只能同時(shí)滿足兩項(xiàng)呢?
我們先看這樣一個(gè)場(chǎng)景,現(xiàn)在我們系統(tǒng)部署了兩份(兩個(gè)節(jié)點(diǎn),web1 和 web2 ),同樣的業(yè)務(wù)代碼,但是維護(hù)的是自己這個(gè)節(jié)點(diǎn)生成的數(shù)據(jù)。但是用戶訪問(wèn)進(jìn)來(lái),可能會(huì)訪問(wèn)到不同的節(jié)點(diǎn)。
但是不管是訪問(wèn)web1 還是web2 ,在用戶參數(shù)數(shù)據(jù) 過(guò)后,這個(gè)數(shù)據(jù)都必須得同步到另外的節(jié)點(diǎn),讓用戶不管訪問(wèn)哪個(gè)節(jié)點(diǎn),都是響應(yīng)他需要的數(shù)據(jù)。如下圖:
分區(qū)容錯(cuò)性
我們先說(shuō)?分區(qū)容錯(cuò)性:也就是說(shuō)呀,就算上面這兩個(gè)節(jié)點(diǎn)之間發(fā)生了網(wǎng)絡(luò)故障,無(wú)法發(fā)生同步的問(wèn)題,但是用戶訪問(wèn)進(jìn)來(lái),不管到哪個(gè)節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)都得單獨(dú)提供服務(wù),這一點(diǎn)對(duì)于互聯(lián)網(wǎng)公司來(lái)說(shuō),是必須要滿足的。
當(dāng) web1 和 web2 之間的網(wǎng)絡(luò)發(fā)生故障,導(dǎo)致數(shù)據(jù)無(wú)法進(jìn)行同步。用戶在web1 上寫(xiě)了數(shù)據(jù),馬上又訪問(wèn)進(jìn)來(lái)讀取數(shù)據(jù),請(qǐng)求到了 web2,但是此時(shí) web2 是沒(méi)有數(shù)據(jù)的。那么我們是 給用戶返回 null ?還是說(shuō)給一些提示,說(shuō)系統(tǒng)不可用,稍后重試呢?
都不妥吧,兄弟。
一致性
如果要保證可用性,那么有數(shù)據(jù)的節(jié)點(diǎn)返回?cái)?shù)據(jù),沒(méi)數(shù)據(jù)的節(jié)點(diǎn)返回 null ,就會(huì)出現(xiàn)用戶那里看到的是一會(huì)兒有數(shù)據(jù),一會(huì)兒沒(méi)有數(shù)據(jù),此時(shí)就存在?一致性 的問(wèn)題。
可用性
如果保證一致性,那么在用戶訪問(wèn)的時(shí)候,不管 web1 還是web2 ,我們可能會(huì)返回一些提示信息,說(shuō)系統(tǒng)不可用,稍后再試等等,保證每次都是一致的。明明我們有數(shù)據(jù)在,但是我們系統(tǒng)卻響應(yīng)的是提示信息,此時(shí)就是 可用性 的問(wèn)題。
由于分區(qū)容錯(cuò)性(P)是必須保證的,那么我們分布式系統(tǒng)就更多是在一致性(CP) 和可用性(AP)上做平衡了,只能同時(shí)滿足兩個(gè)條件。
其實(shí),大家想想,ZK 是不是就是嚴(yán)格實(shí)現(xiàn)了 CP ,而 Eureka 則是保證了 AP。
其實(shí)分布式事物強(qiáng)調(diào)的就是一致性。
幾種分布式事物解決方案
2PC
在說(shuō) 2PC 之前,我們先了解一下?XA規(guī)范 是個(gè)什么東西?
XA規(guī)范 描述了全局的事務(wù)管理器與局部的資源管理器之間的接口。XA規(guī)范的目的是允許多個(gè)資源(如數(shù)據(jù)庫(kù),應(yīng)用服務(wù)器,消息隊(duì)列,等等)在同一事務(wù)中訪問(wèn),這樣可以使ACID屬性跨越應(yīng)用程序而保持有效。
XA 使用 兩階段提交(2PC) 來(lái)保證所有資源同時(shí)提交或回滾任何特定的事務(wù)。
大家想一個(gè)場(chǎng)景,在做單應(yīng)用的時(shí)候,有的同學(xué)連過(guò)兩個(gè)庫(kù)吧?在一個(gè)事物中會(huì)同時(shí)向兩個(gè)系統(tǒng)插入數(shù)據(jù)。但是對(duì)于普通事物來(lái)講,是管不了的。
看下圖(只是舉例這種操作的套路,不局限于下面的業(yè)務(wù)):
一個(gè)服務(wù)里面要去操作兩個(gè)庫(kù),如何保證事物成功呢。
這里我們介紹一個(gè)框架?Atomikos ,他就是實(shí)現(xiàn)了這種 XA 的套路。看代碼:
具體代碼移步 Github?AtomikosJTATest[1]:?https://github.com/heyxyw/learn/blob/master/distributed-transaction/src/main/java/com/zhouq/jta/AtomikosJTATest.java[2]
看到上面的圖了哇,Atomikos 自己實(shí)現(xiàn)了一個(gè)事物管理器。我們獲取的連接都從它哪里拿。
?第一步先開(kāi)啟事務(wù),然后進(jìn)行預(yù)提交,db1 和 db2 都先進(jìn)行預(yù)先執(zhí)行,注意:這里沒(méi)有提交事物。?第二步才是真正的提交事物,由 Atomikos 來(lái)發(fā)起提交的,如果出現(xiàn)異常則發(fā)起回滾操作。
這個(gè)過(guò)程是不是就有兩個(gè)角色了,一個(gè) 事務(wù)管理器,一個(gè)資源管理器(我們這里是 數(shù)據(jù)庫(kù),也可以是其他的組件,消息隊(duì)列什么的)。
整個(gè)執(zhí)行過(guò)程是這樣:
上圖是正常情況,下圖是一方出現(xiàn)故障的情況。
圖片來(lái)自:XA 事務(wù)處理[3]:https://www.infoq.cn/article/xa-transactions-handle[4] ,具體關(guān)于XA 的詳細(xì)講解,可以好好看看。整個(gè)2PC 的流程:
第一階段(提交請(qǐng)求階段):
協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)詢問(wèn)是否可以執(zhí)行提交操作,并開(kāi)始等待各參與者節(jié)點(diǎn)的響應(yīng)。
參與者節(jié)點(diǎn)執(zhí)行詢問(wèn)發(fā)起為止的所有事務(wù)操作,并將Undo信息和Redo信息寫(xiě)入日志。
各參與者節(jié)點(diǎn)響應(yīng)協(xié)調(diào)者節(jié)點(diǎn)發(fā)起的詢問(wèn)。如果參與者節(jié)點(diǎn)的事務(wù)操作實(shí)際執(zhí)行成功,則它返回一個(gè)"同意"消息;如果參與者節(jié)點(diǎn)的事務(wù)操作實(shí)際執(zhí)行失敗,則它返回一個(gè)"中止"消息。
第二階段 (提交執(zhí)行階段):
成功,當(dāng)協(xié)調(diào)者節(jié)點(diǎn)從所有參與者節(jié)點(diǎn)獲得的相應(yīng)消息都為"同意"時(shí):
1.協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)發(fā)出"正式提交"的請(qǐng)求。
2.參與者節(jié)點(diǎn)正式完成操作,并釋放在整個(gè)事務(wù)期間內(nèi)占用的資源。
3.參與者節(jié)點(diǎn)向協(xié)調(diào)者節(jié)點(diǎn)發(fā)送"完成"消息。
4.協(xié)調(diào)者節(jié)點(diǎn)收到所有參與者節(jié)點(diǎn)反饋的"完成"消息后,完成事務(wù)。
失敗,如果任一參與者節(jié)點(diǎn)在第一階段返回的響應(yīng)消息為"終止",或者 協(xié)調(diào)者節(jié)點(diǎn)在第一階段的詢問(wèn)超時(shí)之前無(wú)法獲取所有參與者節(jié)點(diǎn)的響應(yīng)消息時(shí):
1.協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)發(fā)出"回滾操作"的請(qǐng)求。
2.參與者節(jié)點(diǎn)利用之前寫(xiě)入的Undo信息執(zhí)行回滾,并釋放在整個(gè)事務(wù)期間內(nèi)占用的資源。
3.參與者節(jié)點(diǎn)向協(xié)調(diào)者節(jié)點(diǎn)發(fā)送"回滾完成"消息。
4.協(xié)調(diào)者節(jié)點(diǎn)收到所有參與者節(jié)點(diǎn)反饋的"回滾完成"消息后,取消事務(wù)。
有時(shí)候,第二階段也被稱作完成階段,因?yàn)闊o(wú)論結(jié)果怎樣,協(xié)調(diào)者都必須在此階段結(jié)束當(dāng)前事務(wù)。
可靠消息最終一致性方案基于普通的消息隊(duì)列中間件上面我們說(shuō)了兩階段提交的方案,接下來(lái)我們講講怎么基于可靠消息最終一致性方案來(lái)解決分布式事物的問(wèn)題。
這個(gè)方案,就有消息服務(wù)中間件角色參與進(jìn)來(lái)了。我們先看一個(gè)大提的流程圖:
我們以創(chuàng)建訂單下單過(guò)程和 后面出庫(kù) 的流程為例來(lái)講述上面的圖。
在下單邏輯里面(Producer 端),我們先生成一個(gè)訂單的數(shù)據(jù),比如訂單號(hào),數(shù)量等關(guān)鍵的信息,先包裝成一條消息,并把消息的狀態(tài)置為 init ,然后發(fā)送到 獨(dú)立消息服務(wù)中,并且入庫(kù)。
接下來(lái)繼續(xù)處理 下單的其他本地的邏輯。
處理完成后,走到確認(rèn)發(fā)送消息這一步,說(shuō)明我的訂單是能夠下成功的。那么我們?cè)傧蛳⒎?wù)里面發(fā)送一條confirm 的消息,消息服務(wù)里面就可以把這個(gè)訂單的消息狀態(tài)修改為 send 并且,發(fā)送到消息隊(duì)列里面。
接下來(lái),消費(fèi)者端去消費(fèi)這條消息。處理自己這邊的邏輯,處理完成以后,然后反饋消息處理結(jié)果到獨(dú)立消息服務(wù),獨(dú)立消息服務(wù)把消息狀態(tài)置為 end 狀態(tài) ,表示結(jié)束。但是得注意保證接口的冪等性,避免重復(fù)消費(fèi)帶來(lái)的問(wèn)題。
這里面可能出現(xiàn)的問(wèn)題,以及各個(gè)步驟怎么解決的:
1.比如在?prepare 階段就發(fā)生異常,那么這里訂單這塊都不會(huì)下成功。但是我們說(shuō),我們這里是基于可靠消息,得保證我們的消息服務(wù)是正常的。
2.在?comfirm 出現(xiàn)異常,此時(shí)發(fā)送確認(rèn)失敗,但是我們的單已經(jīng)下成功了。這種情況,我們就可以在獨(dú)立消息服務(wù)中起一個(gè)定時(shí)任務(wù),定時(shí)去查詢 消息狀態(tài)為 init?的數(shù)據(jù),去反向查詢 訂單系統(tǒng)中的單號(hào)是否存在,如果存在,那么我們就把消息置為?send 狀態(tài),然后發(fā)送到 消息隊(duì)列里面,如果查詢到不存在的訂單,那么就直接拋棄掉這條消息。所以這里我們的訂單系統(tǒng)得提供批量查詢訂單的接口,還有下游的消費(fèi)系統(tǒng)得保證冪等。保證重復(fù)消費(fèi)的一致性。
3.消息隊(duì)列丟消息或者下游系統(tǒng)一直處理失敗,導(dǎo)致沒(méi)有消息反饋過(guò)來(lái),出現(xiàn)一直是?send 狀態(tài)的消息。此時(shí)獨(dú)立消息我們還需要一個(gè)定時(shí)任務(wù),就是處理這種 send 狀態(tài)的消息,我們可以進(jìn)行重發(fā),直到后面系統(tǒng)消費(fèi)成功為止。
4.最后消費(fèi)者這端,我們?cè)谙M(fèi)的時(shí)候,如果出現(xiàn)消費(fèi)異常,或者是系統(tǒng)bug 導(dǎo)致異常的情況。那么這里我們還可以去記錄日志,如果不是系統(tǒng)代碼問(wèn)題,是網(wǎng)絡(luò)抖動(dòng)導(dǎo)致的,那么在上面第三種情況,消息系統(tǒng)會(huì)重新發(fā)送消息,我們?cè)偬幚砭褪恰?/strong>如果是一直失敗,你就要考慮是不是你的代碼真的有問(wèn)題,有bug 了吧。
5.最后的保底方案,記錄日志,出現(xiàn)問(wèn)題人肉處理數(shù)據(jù)。現(xiàn)在我們系統(tǒng)出現(xiàn)錯(cuò)誤,以目前的技術(shù)手段是沒(méi)辦法做到都靠機(jī)器去解決的,都得靠我們?nèi)恕?/strong>據(jù)我了解,現(xiàn)在很多大廠都會(huì)有這樣的人,專門(mén)處理這種類(lèi)型的問(wèn)題,手動(dòng)去修改數(shù)據(jù)庫(kù)的方式。我們之前待的小廠,基本上都是靠我們自己去寫(xiě) sql 去修改數(shù)據(jù)的,想想,是不是?
貼一下關(guān)鍵的獨(dú)立消息服務(wù)核心邏輯代碼框架:
定時(shí)任務(wù):
基于 RocketMQ實(shí)現(xiàn)
這種方案,跟上面的獨(dú)立消息服務(wù)一致,這里直接去掉獨(dú)立服務(wù),只利用消息隊(duì)列來(lái)實(shí)現(xiàn),也就是阿里的?RocketMQ 。
流程圖如下:
這里的整個(gè)流程跟上面基于消息服務(wù)是一致的。這里就不過(guò)多闡述,具體代碼實(shí)現(xiàn)請(qǐng)參考 :https://www.jianshu.com/p/453c6e7ff81c[5] ,寫(xiě)得非常好。
針對(duì)這里的 可靠消息最終一致性方案 來(lái)說(shuō),我們說(shuō)的 可靠 是指保證消息一定能發(fā)送到消息中間件里面去,保證這里可靠。
對(duì)于下游的系統(tǒng)來(lái)說(shuō),消費(fèi)不成功,一般來(lái)說(shuō)就是采取失敗重試,重試多次不成功,那么就記錄日志,后續(xù)人工介入來(lái)進(jìn)行處理。所以這里得強(qiáng)調(diào)一下,后面的系統(tǒng),一定要處理 冪等,重試,日志 這幾個(gè)東西。
如果是對(duì)于資金類(lèi)的業(yè)務(wù),后續(xù)系統(tǒng)回滾了以后,得想辦法去通知前面的系統(tǒng)也進(jìn)行回滾,或者是發(fā)送報(bào)警由人工來(lái)手工回滾和補(bǔ)償。
TCC 方案
TCC 的全程分為三個(gè)階段,分別是 Try、Confirm、Cancel:
1.Try階段:這個(gè)階段說(shuō)的是對(duì)各個(gè)服務(wù)的資源做檢測(cè)以及對(duì)資源進(jìn)行鎖定或者預(yù)留
2.Confirm階段:這個(gè)階段說(shuō)的是在各個(gè)服務(wù)中執(zhí)行實(shí)際的操作
3.Cancel階段:如果任何一個(gè)服務(wù)的業(yè)務(wù)方法執(zhí)行出錯(cuò),那么這里就需要進(jìn)行補(bǔ)償,就是執(zhí)行已經(jīng)執(zhí)行成功的業(yè)務(wù)邏輯的回滾操作
還是以轉(zhuǎn)賬的例子為例,在跨銀行進(jìn)行轉(zhuǎn)賬的時(shí)候,需要涉及到兩個(gè)銀行的分布式事物,從A 銀行向 B 銀行轉(zhuǎn) 1 塊,如果用TCC 方案來(lái)實(shí)現(xiàn):
大概思路就是這樣的:
1.Try 階段:先把A 銀行賬戶先凍結(jié) 1 塊,B銀行賬戶中的資金給預(yù)加 1 塊。
2.Confirm 階段:執(zhí)行實(shí)際的轉(zhuǎn)賬操作,A銀行賬戶的資金扣減 1塊,B 銀行賬戶的資金增加 1 塊。
3.Cancel 階段:如果任何一個(gè)銀行的操作執(zhí)行失敗,那么就需要回滾進(jìn)行補(bǔ)償,就是比如A銀行賬戶如果已經(jīng)扣減了,但是B銀行賬戶資金增加失敗了,那么就得把A銀行賬戶資金給加回去。
這種方案就比較復(fù)雜了,一步操作要做多個(gè)接口來(lái)配合完成。
以 ByteTCC 框架的實(shí)現(xiàn)例子來(lái)大概描述一下上面的流程,示例地址?https://gitee.com/bytesoft/ByteTCC-sample/tree/master/dubbo-sample[6]
最開(kāi)始 A 銀行賬戶 與 B 銀行賬戶都分別為:amount(數(shù)量)=1000,frozen(凍結(jié)金額)= 0
從A銀行賬戶發(fā)起轉(zhuǎn)賬到 B 銀行賬戶 1 塊:
try 階段:A 銀行賬戶金額減 1,凍結(jié)金額 加 1,B 銀行 賬戶 凍結(jié)金額加 1 。
此時(shí):
?A 銀行賬戶:amount(數(shù)量)= 1000 - 1 = 999,frozen(凍結(jié)金額)= 0 + 1 = 1
?B 銀行賬戶:amount(數(shù)量)= 1000,frozen(凍結(jié)金額)= 0 + 1 = 1
confirm 階段 :A銀行賬戶凍結(jié)金額 減 1,B 銀行賬戶金額 加 1,凍結(jié)金額 減 1
此時(shí):
?A 銀行賬戶:amount(數(shù)量)= 999,frozen(凍結(jié)金額)= 1 - 1 = 0
?B 銀行賬戶:amount(數(shù)量)= 1000 + 1 = 1001,frozen(凍結(jié)金額)= 1 - 1 = 0
cancel 階段:A 銀行賬戶金額 + 1,凍結(jié)金額 -1 ,B 銀行 凍結(jié)金額 -1
此時(shí):
?A 銀行賬戶:amount(數(shù)量)= 999 + 1 = 1000,frozen(凍結(jié)金額)= 1 - 1 = 0
?B 銀行賬戶:amount(數(shù)量)= 1000,frozen(凍結(jié)金額)= 1 - 1 = 0
至此,整個(gè)過(guò)程就演示完畢,大家記得跑一遍代碼。其實(shí)還是蠻復(fù)雜的,有許多接口一起來(lái)配合完成整個(gè)業(yè)務(wù),試想一下,如果我們項(xiàng)目中大量用到 TCC 來(lái)寫(xiě),你受得了?
再提一下 BASE理論
BASE 理論是 Basically Available(基本可用),Soft State(軟狀態(tài))和Eventually Consistent(最終一致性)三個(gè)短語(yǔ)的縮寫(xiě)。
1.基本可用(Basically Available):指分布式系統(tǒng)在出現(xiàn)不可預(yù)知故障的時(shí)候,允許損失部分可用性。
2.軟狀態(tài)( Soft State):指允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認(rèn)為該中間狀態(tài)的存在不會(huì)影響系統(tǒng)的整體可用性,即允許系統(tǒng)在不同節(jié)點(diǎn)的數(shù)據(jù)副本之間進(jìn)行數(shù)據(jù)同步的過(guò)程存在延時(shí)。
3.最終一致( Eventual Consistency):強(qiáng)調(diào)的是所有的數(shù)據(jù)更新操作,在經(jīng)過(guò)一段時(shí)間的同步之后,最終都能夠達(dá)到一個(gè)一致的狀態(tài)。因此,最終一致性的本質(zhì)是需要系統(tǒng)保證最終數(shù)據(jù)能夠達(dá)到一致,而不需要實(shí)時(shí)保證系統(tǒng)數(shù)據(jù)的強(qiáng)一致性。
其核心思想是:
即使無(wú)法做到強(qiáng)一致性(Strong consistency),但每個(gè)應(yīng)用都可以根據(jù)自身的業(yè)務(wù)特點(diǎn),采用適當(dāng)?shù)姆绞絹?lái)使系統(tǒng)達(dá)到最終一致性(Eventual consistency)
到這里大家再想想, 上面 TCC 方案中的賬戶設(shè)計(jì)了一個(gè)凍結(jié)字段?frozen?,這里是不是就是?BASE理論 中間的 軟狀態(tài) 呢 ?
最后
對(duì)存在非常多的微服務(wù)的公司來(lái)說(shuō),服務(wù)之間的調(diào)用異常的復(fù)雜,那么在引入分布式事物的過(guò)程中,你需要考慮加入分布式事物后,系統(tǒng)實(shí)現(xiàn)起來(lái)的復(fù)雜性和開(kāi)發(fā)成本,或者說(shuō)哪些地方根本就不需要搞分布式事物。
其實(shí)沒(méi)必要到處都搞分布式事物,對(duì)于大多數(shù)的業(yè)務(wù)來(lái)說(shuō),其實(shí)我們并不需要做分布式事物,直接做日志,做監(jiān)控就好了。然后出現(xiàn)問(wèn)題,手工去處理,一個(gè)月也不會(huì)有那么多的問(wèn)題的。如果你天天都出現(xiàn)這些問(wèn)題,你是不是要好好去排查排查你的代碼Bug了。
對(duì)于資金類(lèi)的場(chǎng)景,那么基本上會(huì)采用分布式事物方案來(lái)保證,像其他的服務(wù),會(huì)員,積分,商品信息呀這些,可能就不需要這么去搞了。
作者介紹:喬二爺,在成都喬二爺這個(gè)名字是之前身邊的同事給取的,也不知道為啥。也習(xí)慣了他們這樣叫我。
一直待在相對(duì)傳統(tǒng)一點(diǎn)的企業(yè),有四年半的 Java 開(kāi)發(fā)經(jīng)驗(yàn),會(huì)點(diǎn)大數(shù)據(jù)的內(nèi)容,也跟客戶打過(guò)一年的交道,還帶過(guò) 10個(gè)月 10人+的技術(shù)團(tuán)隊(duì),有一定的協(xié)調(diào)組織能力,能夠理解 boss 的工作內(nèi)容,也能很好的配合別人做事。
【End】
重磅消息:為了回饋?zhàn)x者朋友,老王準(zhǔn)備了500元的微信紅包,點(diǎn)擊參與領(lǐng)取
關(guān)注下方二維碼,訂閱更多精彩內(nèi)容。
轉(zhuǎn)發(fā)朋友圈,是對(duì)我最大的支持。
總結(jié)
以上是生活随笔為你收集整理的面试必备的分布式事物方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: MySQL 面试题汇总
- 下一篇: Java面试详解(2020版):500+