圖文精講java常見(jiàn)分布式事務(wù)理論與解決方案
如何解決某個(gè)節(jié)點(diǎn)故障的問(wèn)題?如何解決數(shù)據(jù)一致性的問(wèn)題?如何解決數(shù)據(jù)傾斜的問(wèn)題?
CAP理論
先從定義開(kāi)始:
C(Consistence):一致性
所有的節(jié)點(diǎn)訪問(wèn)的是最新的數(shù)據(jù)副本,這是什么意思呢?我們知道在分布式系統(tǒng)中,為了高可用,往往一個(gè)節(jié)點(diǎn)會(huì)有若干個(gè)數(shù)據(jù)副本,簡(jiǎn)稱Follower節(jié)點(diǎn),比較常見(jiàn)的模式是我們的數(shù)據(jù)更新一般會(huì)寫(xiě)入Leader節(jié)點(diǎn),然后會(huì)同步給Follower節(jié)點(diǎn),當(dāng)我們讀取數(shù)據(jù)的時(shí)候,不論從哪個(gè)節(jié)點(diǎn)讀取都可以讀到最新的數(shù)據(jù),這就是一致性。
A、B、C可以得到同樣的數(shù)據(jù)。
A(Availability):可用性
非故障節(jié)點(diǎn)可以正常的操作,簡(jiǎn)單來(lái)說(shuō)就是客戶端一直可以正常訪問(wèn)并得到系統(tǒng)的正常響應(yīng),從用戶角度來(lái)看就是不會(huì)出現(xiàn)系統(tǒng)操作失敗或者訪問(wèn)超時(shí)等問(wèn)題,但是系統(tǒng)內(nèi)部可能會(huì)出現(xiàn)網(wǎng)絡(luò)延遲等問(wèn)題。
C節(jié)點(diǎn)因?yàn)樽陨韱?wèn)題不可用,正常情況會(huì)被剔除,B節(jié)點(diǎn)與A節(jié)點(diǎn)之間可能存在同步延遲,但是B節(jié)點(diǎn)本身沒(méi)有故障,所以B節(jié)點(diǎn)是可用的。
P(Partition tolerance):分區(qū)容錯(cuò)性
網(wǎng)絡(luò)的問(wèn)題錯(cuò)綜復(fù)雜,分布式系統(tǒng)肯定是要考慮這一點(diǎn)的,如果出現(xiàn)某個(gè)節(jié)點(diǎn)因?yàn)榫W(wǎng)絡(luò)等問(wèn)題造成數(shù)據(jù)不一致,或者數(shù)據(jù)延遲很久才同步過(guò)來(lái),雖然會(huì)影響部分節(jié)點(diǎn)數(shù)據(jù)的時(shí)效性,但是服務(wù)節(jié)點(diǎn)依然是可用的,分布式系統(tǒng)要能容忍這種情況的。
B對(duì)應(yīng)的節(jié)點(diǎn)雖然和Leader斷了聯(lián)系,但是依然可以對(duì)外服務(wù),只不過(guò)提供的是老數(shù)據(jù)。
在分布式系統(tǒng)中,CAP是無(wú)法同時(shí)滿足的,首先由于存在多節(jié)點(diǎn),并且網(wǎng)絡(luò)傳輸需要時(shí)間,所以可能會(huì)存在延遲,那么節(jié)點(diǎn)之間的數(shù)據(jù)我們無(wú)法保證某一時(shí)刻完全一致,因此P(分區(qū)容錯(cuò)性)是要滿足的。在P滿足的情況下,為什么說(shuō)CA不能同時(shí)滿足呢?我們來(lái)通過(guò)假設(shè)看一看,如果CA同時(shí)滿足會(huì)怎么樣。
- 假設(shè)現(xiàn)在要求滿足C(一致性),那么就是說(shuō)所有的節(jié)點(diǎn)在某一刻提供的數(shù)據(jù)都必須一致,我們知道在P的情況,是不可能保證的,要保證的話,就只能把其他節(jié)點(diǎn)全部干掉,比如禁止讀寫(xiě),那這其實(shí)就是和A是相悖的(某些節(jié)點(diǎn)雖然延遲,但是節(jié)點(diǎn)本身可用)。
- 假設(shè)現(xiàn)在要求滿足A(可用性),那么就是說(shuō)只要節(jié)點(diǎn)本身沒(méi)什么問(wèn)題,就可以對(duì)外提供服務(wù),哪怕有點(diǎn)數(shù)據(jù)延遲,很明顯這肯定是和C相悖的。
在實(shí)際的業(yè)務(wù)中,我們需要根據(jù)業(yè)務(wù)的場(chǎng)景來(lái)決定使用CP,還是AP。比如對(duì)一些和錢(qián)掛鉤的業(yè)務(wù),數(shù)據(jù)的一致性按道理應(yīng)該是最重要的,因此一般會(huì)采用CP,而對(duì)于一些不影響主體功能的業(yè)務(wù),比如像新聞的閱讀量,不同的用戶看到的閱讀量不一樣并不會(huì)造成什么影響,可以采用AP。
BASE理論
由于CAP理論中C和A無(wú)法兼得,eBay的架構(gòu)師提出了BASE理論,BASE理論主要是在CA之間做文章,它不要求強(qiáng)一致性,因此可以滿足一定的可用性。我們還是先從定義開(kāi)始:
BA(Basically Available):基本可用
注意這個(gè)和不可用不是一回事,在分布式系統(tǒng)中出現(xiàn)不可預(yù)估的故障時(shí),允許損失部分可用性,保證核心功能可用,比如正常一個(gè)接口響應(yīng)200ms,在出現(xiàn)故障時(shí)響應(yīng)超過(guò)1s,雖然響應(yīng)時(shí)間變長(zhǎng)了,但是接口還是可以對(duì)外提供服務(wù)的,再比如對(duì)于一個(gè)視頻網(wǎng)站,在突發(fā)流量到來(lái)時(shí),把視頻的彈幕服務(wù)打掛了,但是視頻的播放功能依然正常。
S(Soft-state):軟狀態(tài)
即分布式系統(tǒng)允許存在一個(gè)中間的狀態(tài),但是這個(gè)中間狀態(tài)并不會(huì)對(duì)服務(wù)造成嚴(yán)重的影響,比如對(duì)于主從復(fù)制這種,允許從節(jié)點(diǎn)短暫的延遲。
E(Eventually Consistent):最終一致性
由于軟狀態(tài)的存在,系統(tǒng)對(duì)延遲是可以容忍的,但是在一段時(shí)間后,延遲的數(shù)據(jù)需要最終保持一致。
總的來(lái)說(shuō),BASE理論適用性應(yīng)該更廣泛,很多時(shí)候我們并不要求數(shù)據(jù)的強(qiáng)一致性,只要在短暫的延時(shí)之后能達(dá)到一致性也是可以的。
一致性hash
hash這個(gè)詞對(duì)我們來(lái)說(shuō)并不陌生,以緩存服務(wù)器來(lái)說(shuō),一般會(huì)在線上配置好幾臺(tái)服務(wù)器,然后根據(jù)hash來(lái)決定請(qǐng)求哪臺(tái)緩存服務(wù),比如常見(jiàn)的就是取模方式?hash(key)%num?來(lái)獲取目標(biāo)機(jī)器。
假設(shè)現(xiàn)在有3臺(tái)緩存服務(wù)器,并且當(dāng)前有3個(gè)緩存的key,分別是k0,k1,k2,在經(jīng)過(guò)hash以后,它們的分布情況如下:
hash(k0)%3=0 #No.0 hash(k1)%3=1 #No.1 hash(k2)%3=2 #No.2
很幸運(yùn),分布的非常均勻,每臺(tái)機(jī)器一個(gè)。某天,由于線上要做個(gè)活動(dòng),預(yù)計(jì)訪問(wèn)量會(huì)加大,需要選擇加一臺(tái)服務(wù)器來(lái)分擔(dān)壓力,于是經(jīng)過(guò)hash之后,k0,k1,k2的分布情況如下:
hash(k0)%4=0 #No.1 hash(k1)%4=1 #No.2 hash(k2)%4=2 #No.3
- k0的目標(biāo)緩存服務(wù)器由原本的No.0變成了No.1
- k1的目標(biāo)緩存服務(wù)器由原本的No.1變成了No.2
- k2的目標(biāo)緩存服務(wù)器由原本的No.2變成了No.3
可以發(fā)現(xiàn)因?yàn)樘砑恿艘慌_(tái)緩存節(jié)點(diǎn),導(dǎo)致了k0,k1,k2原來(lái)的緩存全部失效了,這似乎有點(diǎn)問(wèn)題,類似緩存雪崩,嚴(yán)重的話會(huì)對(duì)DB造成很大的壓力,造成這個(gè)問(wèn)題的主要原因是因?yàn)槲覀兗恿艘粋€(gè)節(jié)點(diǎn),導(dǎo)致hash結(jié)果發(fā)生了變動(dòng),此時(shí)的hash可以說(shuō)是不穩(wěn)定的。
為了解決rehash不穩(wěn)定的問(wèn)題,于是出現(xiàn)了一致性hash算法。一致性hash的原理比較簡(jiǎn)單,首先存在一個(gè)hash圓環(huán),這個(gè)圓環(huán)可以存放 0-2^32-1 個(gè)節(jié)點(diǎn)。
- 第一步就是把我們的目標(biāo)服務(wù)器節(jié)點(diǎn)通過(guò)hash映射到這個(gè)環(huán)上
- 第二步根據(jù)我們需要查找的key,它應(yīng)該也對(duì)應(yīng)hash環(huán)上的某個(gè)位置
也許你會(huì)問(wèn),這k0、k1、k2也沒(méi)和某個(gè)緩存節(jié)點(diǎn)對(duì)上呀~,這就是一致性hash不同的地方,它此時(shí)查找的方式并不是?hash(key)=某個(gè)節(jié)點(diǎn),而是根據(jù)key的位置,順時(shí)針找到第一個(gè)節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)就是當(dāng)下這個(gè)key的目標(biāo)節(jié)點(diǎn)。
我們?cè)賮?lái)看看在一致性hash的情況下,新增一個(gè)節(jié)點(diǎn)會(huì)發(fā)生什么。
此時(shí)唯一的變動(dòng)就是k0原本應(yīng)該打到cache0節(jié)點(diǎn)的,現(xiàn)在卻打到了我們新加的節(jié)點(diǎn)cache3上,而k1,k2是不變的,也就是說(shuō)有且只有k0的緩存失效了,相比之前,大大降低了緩存失效的面積。
當(dāng)然這樣的節(jié)點(diǎn)分布算是比較理想的了,如果我們的節(jié)點(diǎn)是這樣分布的:
幾個(gè)cache節(jié)點(diǎn)分布的比較集中,由于順時(shí)針查找法,所以最終k0,k1,k2都落在cache0節(jié)點(diǎn)上,也就是說(shuō)cache1、cache2基本就是多余的,所以為了解決這種數(shù)據(jù)傾斜的問(wèn)題,一致性hash又引入了虛擬節(jié)點(diǎn)的概念,每個(gè)節(jié)點(diǎn)可以有若干個(gè)虛擬節(jié)點(diǎn),比如:
- cache0->cache0#1
- cache1->cache1#1
- cache2->cache2#1
虛擬節(jié)點(diǎn)并不是真正的服務(wù)節(jié)點(diǎn),它只是一個(gè)影子,它的目的就是站坑位,讓節(jié)點(diǎn)更加分散,更加均勻。
這樣通過(guò)映射出虛擬節(jié)點(diǎn)以后,k0打到cache2,k1打到cache0,k2打到cache1,虛擬節(jié)點(diǎn)越多,理論分布的越均勻。
Gossip協(xié)議
集群往往是由多個(gè)節(jié)點(diǎn)共同組成的,當(dāng)一個(gè)節(jié)點(diǎn)加入集群或者一個(gè)節(jié)點(diǎn)從集群中下線的時(shí)候,都需要讓集群中其他的節(jié)點(diǎn)知道,這樣才能將數(shù)據(jù)信息分享給新節(jié)點(diǎn)而忽略下線節(jié)點(diǎn)。
A、B、C節(jié)點(diǎn)之間可以互相傳遞消息,但是D節(jié)點(diǎn)在下線之后會(huì)被廣播告訴其他存活節(jié)點(diǎn)。
這樣的廣播協(xié)議就是今天要說(shuō)Gossip協(xié)議,Gossip協(xié)議也叫Epidemic協(xié)議(流行病協(xié)議),當(dāng)一個(gè)消息到來(lái)時(shí),通過(guò)Gossip協(xié)議就可以像病毒一樣感染全部集群節(jié)點(diǎn),當(dāng)然我們利用的是它這個(gè)極強(qiáng)的散播能力。
Gossip的過(guò)程是由一個(gè)種子節(jié)點(diǎn)發(fā)起的,當(dāng)一個(gè)種子節(jié)點(diǎn)有信息需要同步到網(wǎng)絡(luò)中的其他節(jié)點(diǎn)時(shí),它會(huì)隨機(jī)的選擇周?chē)鷰讉€(gè)節(jié)點(diǎn)散播消息,收到消息的節(jié)點(diǎn)也會(huì)重復(fù)該過(guò)程,直至最終網(wǎng)絡(luò)中所有的節(jié)點(diǎn)都收到了消息。這個(gè)過(guò)程可能需要一定的時(shí)間,所以不能保證某個(gè)時(shí)間點(diǎn)所有的節(jié)點(diǎn)都有該條消息,但是理論上最終所有節(jié)點(diǎn)都會(huì)收到消息,因此它是一個(gè)最終一致性協(xié)議。
Gossip協(xié)議的特點(diǎn):
- Gossip協(xié)議是周期性散播消息,每隔一段時(shí)間傳播一次
- 被感染的節(jié)點(diǎn),每次可以繼續(xù)散播N個(gè)節(jié)點(diǎn)
- 每次散播消息時(shí),都會(huì)選擇尚未發(fā)送過(guò)的節(jié)點(diǎn)進(jìn)行散播
- 收到消息的節(jié)點(diǎn),不會(huì)向發(fā)送的節(jié)點(diǎn)散播
- 同一個(gè)節(jié)點(diǎn)可能會(huì)收到重復(fù)的消息,因?yàn)榭赡芡瑫r(shí)多個(gè)節(jié)點(diǎn)正好向它散播
- 集群是去中心化的,節(jié)點(diǎn)之間都是平等的
- 消息的散播不用等接收節(jié)點(diǎn)的ack,即消息可能會(huì)丟失,但是最終應(yīng)該會(huì)被感染
我們來(lái)看個(gè)例子:
- 種子節(jié)點(diǎn)是A
- A節(jié)點(diǎn)選擇B、C節(jié)點(diǎn)進(jìn)行散播
- C散播到D,B散播D和E,可以發(fā)現(xiàn)D收到兩次
- D散播到F,最終整個(gè)網(wǎng)絡(luò)都同步到了消息
Gossip有點(diǎn)類似圖的廣度優(yōu)先遍歷算法,一般用于網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)信息的分享和維護(hù),像redis、consul都有使用到。
Raft算法
分布式協(xié)議的難點(diǎn)之一就是數(shù)據(jù)的一致性,當(dāng)由多個(gè)節(jié)點(diǎn)組成的集群中只有一個(gè)節(jié)點(diǎn)收到數(shù)據(jù),我們就算成功的話,風(fēng)險(xiǎn)太大,當(dāng)要求所有節(jié)點(diǎn)都收到數(shù)據(jù)才響應(yīng)成功,性能又太差,所以一般會(huì)在數(shù)據(jù)的安全和性能之間做個(gè)折中,只要保證絕大部分節(jié)點(diǎn)同步數(shù)據(jù)成功,我們就算成功,Raft算法作為比較知名的一致性算法,被廣泛應(yīng)用于許多中間件中,比如像etcd,接下來(lái)我們就看看Raft算法是如何工作的。
首先介紹下在Raft算法中,幾種情況下每個(gè)節(jié)點(diǎn)對(duì)應(yīng)的角色:
Leader
節(jié)點(diǎn):同大多數(shù)分布式中的Leader節(jié)點(diǎn)一樣,數(shù)據(jù)的變更都是通過(guò)它的
Follower
節(jié)點(diǎn):Leader節(jié)點(diǎn)的追隨者,負(fù)責(zé)復(fù)制數(shù)據(jù)并且在選舉時(shí)候投票的節(jié)點(diǎn)
Candidate
候選節(jié)點(diǎn):參與選舉的節(jié)點(diǎn),就是Follower節(jié)點(diǎn)參與選舉時(shí)會(huì)切換的角色
Raft算法將一致性問(wèn)題分解為兩個(gè)的子問(wèn)題,Leader選舉和狀態(tài)復(fù)制。
選舉
首先我們來(lái)看看Leader的選舉,系統(tǒng)在剛開(kāi)始的時(shí)候,所有節(jié)點(diǎn)都為Follower節(jié)點(diǎn),這時(shí)大家都有機(jī)會(huì)參與選舉,也就是把自己變成Candidate,但是如果每個(gè)Follower節(jié)點(diǎn)都變成Candidate那么就會(huì)陷入無(wú)限的死循環(huán),于是每個(gè)Follower都一個(gè)定時(shí)器,并且定時(shí)器的時(shí)間是隨機(jī)的,當(dāng)某個(gè)Follower的定時(shí)器時(shí)間走完之后,會(huì)確認(rèn)當(dāng)前是否存在Leader節(jié)點(diǎn),如果不存在就會(huì)把自己變成Candidate,這時(shí)會(huì)投自己1票,同時(shí)告訴其它節(jié)點(diǎn),讓它們來(lái)投票,當(dāng)拿到超過(guò)半數(shù)以上的投票時(shí),當(dāng)前的Candidate就會(huì)變成Leader節(jié)點(diǎn)。
- 由于A節(jié)點(diǎn)的定時(shí)器時(shí)間最短(10ms),所以A會(huì)成為Candidate
- A投自己一票,同時(shí)B、C也投出自己的同意票,因此A會(huì)變成Leader節(jié)點(diǎn),同時(shí)會(huì)記錄是第M任。這個(gè)M是做版本校驗(yàn)的,比如一個(gè)編號(hào)是10的節(jié)點(diǎn),收到了一個(gè)編號(hào)是9的節(jié)點(diǎn)的投票請(qǐng)求,那么就會(huì)拒絕這個(gè)請(qǐng)求。
在Leader節(jié)點(diǎn)選舉出來(lái)以后,Leader節(jié)點(diǎn)會(huì)不斷的發(fā)送心跳給其它Follower節(jié)點(diǎn)證明自己是活著的,其他Follower節(jié)點(diǎn)在收到心跳后會(huì)清空自己的定時(shí)器,并回復(fù)給Leader,因?yàn)榇藭r(shí)沒(méi)必要觸發(fā)選舉了。
如果Leader節(jié)點(diǎn)在某一刻掛了,那么Follower節(jié)點(diǎn)就不會(huì)收到心跳,因此在定時(shí)器到來(lái)時(shí)就會(huì)觸發(fā)新一輪的選舉,流程還是一樣,但是如果恰巧兩個(gè)Follower都變成了Candidate,并且都得到了同樣的票數(shù),那么此時(shí)就會(huì)陷入僵局,為了打破僵局,這時(shí)每個(gè)Candidate都會(huì)隨機(jī)推遲一段時(shí)間再次請(qǐng)求投票,當(dāng)然一般情況下,就是先來(lái)先得,優(yōu)先跑完定時(shí)器的Candidate理論成為L(zhǎng)eader的概率更大。
好的選舉流程大致如上,接下來(lái)我們來(lái)看看數(shù)據(jù)的復(fù)制。
復(fù)制
當(dāng)Leader節(jié)點(diǎn)收到Client的請(qǐng)求變更時(shí),會(huì)把變更記錄到log中,然后Leader會(huì)將這個(gè)變更隨著下一次的心跳通知給Follower節(jié)點(diǎn),收到消息的Follower節(jié)點(diǎn)把變更同樣寫(xiě)入日志中,然后回復(fù)Leader節(jié)點(diǎn),當(dāng)Leader收到大多數(shù)的回復(fù)后,就把變更寫(xiě)入自己的存儲(chǔ)空間,同時(shí)回復(fù)client,并告訴Follower應(yīng)用此log。至此,集群就變更達(dá)成了共識(shí)。
最后,Raft算法是能夠?qū)崿F(xiàn)分布式系統(tǒng)強(qiáng)一致性的算法,每個(gè)系統(tǒng)節(jié)點(diǎn)有三種狀態(tài)Leader、Follower、Candidate,實(shí)現(xiàn)Raft算法兩個(gè)最重要的事是:主的選舉和日志的復(fù)制。
分布式事務(wù)
事務(wù)相信大家不陌,事務(wù)的本質(zhì)是要么一起向前沖,要么一起保持不動(dòng)。對(duì)于MySQL的InnoDB來(lái)說(shuō),我們只需要執(zhí)行begin、commit就行,有時(shí)候我們可能需要回滾rollback。但是這是在同一數(shù)據(jù)庫(kù)的前提下,如果我們的數(shù)據(jù)表分庫(kù)了或者說(shuō)我們要操作的資源在不同的網(wǎng)絡(luò)節(jié)點(diǎn)上該怎么辦?這就得用到我們今天要說(shuō)的分布式事務(wù)了,分布式事務(wù)有2PC、3PC、TCC等, 但是無(wú)論哪種都無(wú)法保證完美的ACID,我們來(lái)一起看看是怎么回事吧。
2PC
從名字可以看出它是分兩個(gè)階段的,所以它也叫做二階段提交,即準(zhǔn)備和提交,2PC要求有個(gè)事務(wù)的協(xié)調(diào)者,相比常規(guī)的事務(wù),我們的請(qǐng)求是發(fā)給這個(gè)協(xié)調(diào)者的,然后由協(xié)調(diào)者幫我們協(xié)調(diào)各個(gè)節(jié)點(diǎn)資源的提交。
- 準(zhǔn)備階段:協(xié)調(diào)者會(huì)讓各個(gè)參與事務(wù)的參與者,把除了提交之外所有的事情都干好,也就是就等著提交了
- 提交階段:協(xié)調(diào)者收到各個(gè)參與者的準(zhǔn)備消息后,根據(jù)準(zhǔn)備情況通知各個(gè)參與者提交(commit)或者回滾(rollback)
可以發(fā)現(xiàn)整個(gè)過(guò)程非常依賴協(xié)調(diào)者,如果協(xié)調(diào)者掛了,那么整個(gè)分布式事務(wù)就不可用,所以一般建議協(xié)調(diào)者至少有個(gè)備份節(jié)點(diǎn)。
如果協(xié)調(diào)者在收到所有節(jié)點(diǎn)的ok之后,在準(zhǔn)備發(fā)送commit消息的時(shí)候,由于網(wǎng)絡(luò)問(wèn)題,導(dǎo)致其中一個(gè)節(jié)點(diǎn)始終收不到消息,那么收不到消息的節(jié)點(diǎn)就會(huì)一直占著資源不釋放,出現(xiàn)這種情況的時(shí)候,建議協(xié)調(diào)者有個(gè)重試功能,在commit失敗之后,不停的重試,直至成功。2PC協(xié)議是一種強(qiáng)一致性協(xié)議,它是同步阻塞的,所以在高并發(fā)的場(chǎng)景它的性能可能還會(huì)有問(wèn)題。
3PC
2PC存在一些問(wèn)題,比如協(xié)調(diào)者從掛了到恢復(fù)后并不知道當(dāng)前節(jié)點(diǎn)的狀態(tài),現(xiàn)在應(yīng)該做什么(是該提交還是回滾等等),還有就是當(dāng)發(fā)生網(wǎng)絡(luò)問(wèn)題的時(shí)候,無(wú)法通信的節(jié)點(diǎn)只會(huì)傻傻的等待,造成資源一直處于鎖定狀態(tài)。鑒于這些問(wèn)題,出現(xiàn)了3PC。
首先3PC顧名思義,會(huì)分為3個(gè)階段,分別是準(zhǔn)備階段、預(yù)提交階段和提交階段。
- 準(zhǔn)備階段:主要是詢問(wèn)參與者自身的狀況,比如你的負(fù)載情況如何?能參與接下來(lái)的任務(wù)吧?
- 預(yù)提交階段:除了commit之外的所有準(zhǔn)備工作,就等著commit了
- 提交階段:執(zhí)行真正的commit或者rollback
如果在事務(wù)期間,有新的協(xié)調(diào)者頂替進(jìn)來(lái),它就可以根據(jù)一個(gè)參與者的狀態(tài)來(lái)判斷當(dāng)前應(yīng)該干嘛,比如如果一個(gè)參與者處于提交階段,那么表明當(dāng)前的事務(wù)正處于提交階段。當(dāng)因?yàn)榫W(wǎng)絡(luò)問(wèn)題某個(gè)節(jié)點(diǎn)一直收不到提交信息,那么此時(shí)也不會(huì)傻等了,會(huì)有超時(shí)時(shí)間,當(dāng)超時(shí)時(shí)間過(guò)去了,節(jié)點(diǎn)可以自動(dòng)提交,但是這里有個(gè)問(wèn)題,對(duì)于參與者節(jié)點(diǎn)來(lái)說(shuō),當(dāng)前應(yīng)該是commit還是rollback呢?
其實(shí)2PC和3PC都無(wú)法保證絕對(duì)的一致性,因?yàn)槟硞€(gè)參與者節(jié)點(diǎn)可能就是因?yàn)榫W(wǎng)絡(luò)問(wèn)題收不到消息,但是其他參與者節(jié)點(diǎn)已經(jīng)提交了事務(wù),一般為了預(yù)防這種問(wèn)題,最好加一個(gè)報(bào)警,比如監(jiān)控到事務(wù)異常的時(shí)候,通過(guò)腳本自動(dòng)補(bǔ)償差異的信息。
TCC
TCC事務(wù)的全程是Try、Commit、Cancel,TCC事務(wù)使用場(chǎng)景更貼近實(shí)際應(yīng)用,因此它的使用也更廣泛。
Try
:Try這個(gè)過(guò)程,一般表示鎖定資源的過(guò)程,比如常見(jiàn)的下單,在try階段,我們不是真正的減庫(kù)存,而是把下單的庫(kù)存給鎖定住。
Commit
:真正的執(zhí)行業(yè)務(wù)邏輯了,帶提交的。
Cancel
:撤銷(xiāo),如果Commit失敗可以把鎖定的資源釋放回來(lái)
TCC對(duì)應(yīng)用的侵入性強(qiáng)。業(yè)務(wù)邏輯的每個(gè)分支都需要實(shí)現(xiàn)try、confirm、cancel三個(gè)操作,代碼改造成本高。在出現(xiàn)網(wǎng)絡(luò)或者其他系統(tǒng)故障時(shí),TCC要根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景實(shí)現(xiàn)對(duì)應(yīng)的回滾邏輯。Commit或者Cancel有可能會(huì)重試,因此對(duì)應(yīng)的部分最好支持冪等。
最后其實(shí)上面3種分布式事務(wù)理論上都無(wú)法保證絕對(duì)的一致性,因?yàn)闊o(wú)法解決網(wǎng)絡(luò)等帶來(lái)的意外因素,要解決它,要么只能無(wú)限重試,但是這個(gè)無(wú)限重試最好通過(guò)消息隊(duì)列+守護(hù)進(jìn)程的方式來(lái)自動(dòng)補(bǔ)數(shù)據(jù),前提還是得保證消息隊(duì)列不丟失數(shù)據(jù)??傊粌H僅是分布式事務(wù)會(huì)帶來(lái)這些問(wèn)題,分布式本身也會(huì)帶來(lái)許許多多的問(wèn)題,沒(méi)有絕對(duì)的解決方案,只有更好的解決方案。
以上就是圖文精講java常見(jiàn)分布式事務(wù)理論與解決方案的詳細(xì)內(nèi)容,更多關(guān)于分布式理論與解決方案的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java基于Guava Retrying實(shí)現(xiàn)重試功能
這篇文章主要介紹了Java基于Guava Retrying實(shí)現(xiàn)重試功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07ssm實(shí)現(xiàn)分頁(yè)查詢的實(shí)例
下面小編就為大家?guī)?lái)一篇ssm實(shí)現(xiàn)分頁(yè)查詢的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11Java分頁(yè)查詢--分頁(yè)顯示(實(shí)例講解)
下面小編就為大家?guī)?lái)一篇Java分頁(yè)查詢--分頁(yè)顯示(實(shí)例講解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08Mybatis Plus 代碼生成器的實(shí)現(xiàn)
這篇文章主要介紹了Mybatis Plus 代碼生成器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Java基本概念監(jiān)視器實(shí)習(xí)原理解析
這篇文章主要介紹了Java基本概念監(jiān)視器實(shí)習(xí)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08java volatile關(guān)鍵字的含義詳細(xì)介紹
這篇文章主要介紹了java volatile關(guān)鍵字的含義詳解的相關(guān)資料,需要的朋友可以參考下2016-12-12Spring事件監(jiān)聽(tīng)機(jī)制ApplicationEvent方式
這篇文章主要介紹了Spring事件監(jiān)聽(tīng)機(jī)制ApplicationEvent方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09