本人免費(fèi)整理了Java高級(jí)資料,涵蓋了Java、redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并發(fā)分布式等教程,一共30G,需要自己領(lǐng)取。
傳送門:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q
一、分布式鎖
創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)與策劃設(shè)計(jì),美蘭網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10余年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:美蘭等地區(qū)。美蘭做網(wǎng)站價(jià)格咨詢:18982081108
數(shù)據(jù)庫的唯一索引
Redis 的 SETNX 指令
Redis 的 RedLock 算法
Zookeeper 的有序節(jié)點(diǎn)
二、分布式事務(wù)
2PC
本地消息表
三、CAP
一致性
可用性
分區(qū)容忍性
權(quán)衡
四、BASE
基本可用
軟狀態(tài)
最終一致性
五、Paxos
執(zhí)行過程
約束條件
六、Raft
單個(gè) Candidate 的競選
多個(gè) Candidate 競選
數(shù)據(jù)同步
在單機(jī)場景下,可以使用語言的內(nèi)置鎖來實(shí)現(xiàn)進(jìn)程同步。但是在分布式場景下,需要同步的進(jìn)程可能位于不同的節(jié)點(diǎn)上,那么就需要使用分布式鎖。
阻塞鎖通常使用互斥量來實(shí)現(xiàn):
互斥量為 0 表示有其它進(jìn)程在使用鎖,此時(shí)處于鎖定狀態(tài);
互斥量為 1 表示未鎖定狀態(tài)。
1 和 0 可以用一個(gè)整型值表示,也可以用某個(gè)數(shù)據(jù)是否存在表示。
獲得鎖時(shí)向表中插入一條記錄,釋放鎖時(shí)刪除這條記錄。唯一索引可以保證該記錄只被插入一次,那么就可以用這個(gè)記錄是否存在來判斷是否存于鎖定狀態(tài)。
存在以下幾個(gè)問題:
鎖沒有失效時(shí)間,解鎖失敗的話其它進(jìn)程無法再獲得該鎖。
只能是非阻塞鎖,插入失敗直接就報(bào)錯(cuò)了,無法重試。
不可重入,已經(jīng)獲得鎖的進(jìn)程也必須重新獲取鎖。
使用 SETNX(set if not exist)指令插入一個(gè)鍵值對(duì),如果 Key 已經(jīng)存在,那么會(huì)返回 False,否則插入成功并返回 True。
SETNX 指令和數(shù)據(jù)庫的唯一索引類似,保證了只存在一個(gè) Key 的鍵值對(duì),那么可以用一個(gè) Key 的鍵值對(duì)是否存在來判斷是否存于鎖定狀態(tài)。
EXPIRE 指令可以為一個(gè)鍵值對(duì)設(shè)置一個(gè)過期時(shí)間,從而避免了數(shù)據(jù)庫唯一索引實(shí)現(xiàn)方式中釋放鎖失敗的問題。
使用了多個(gè) Redis 實(shí)例來實(shí)現(xiàn)分布式鎖,這是為了保證在發(fā)生單點(diǎn)故障時(shí)仍然可用。
嘗試從 N 個(gè)互相獨(dú)立 Redis 實(shí)例獲取鎖;
計(jì)算獲取鎖消耗的時(shí)間,只有當(dāng)這個(gè)時(shí)間小于鎖的過期時(shí)間,并且從大多數(shù)(N / 2 + 1)實(shí)例上獲取了鎖,那么就認(rèn)為鎖獲取成功了;
如果鎖獲取失敗,就到每個(gè)實(shí)例上釋放鎖。
Zookeeper 提供了一種樹形結(jié)構(gòu)的命名空間,/app1/p_1 節(jié)點(diǎn)的父節(jié)點(diǎn)為 /app1。
永久節(jié)點(diǎn):不會(huì)因?yàn)闀?huì)話結(jié)束或者超時(shí)而消失;
臨時(shí)節(jié)點(diǎn):如果會(huì)話結(jié)束或者超時(shí)就會(huì)消失;
有序節(jié)點(diǎn):會(huì)在節(jié)點(diǎn)名的后面加一個(gè)數(shù)字后綴,并且是有序的,例如生成的有序節(jié)點(diǎn)為 /lock/node-0000000000,它的下一個(gè)有序節(jié)點(diǎn)則為 /lock/node-0000000001,以此類推。
為一個(gè)節(jié)點(diǎn)注冊監(jiān)聽器,在節(jié)點(diǎn)狀態(tài)發(fā)生改變時(shí),會(huì)給客戶端發(fā)送消息。
創(chuàng)建一個(gè)鎖目錄 /lock;
當(dāng)一個(gè)客戶端需要獲取鎖時(shí),在 /lock 下創(chuàng)建臨時(shí)的且有序的子節(jié)點(diǎn);
客戶端獲取 /lock 下的子節(jié)點(diǎn)列表,判斷自己創(chuàng)建的子節(jié)點(diǎn)是否為當(dāng)前子節(jié)點(diǎn)列表中序號(hào)最小的子節(jié)點(diǎn),如果是則認(rèn)為獲得鎖;否則監(jiān)聽自己的前一個(gè)子節(jié)點(diǎn),獲得子節(jié)點(diǎn)的變更通知后重復(fù)此步驟直至獲得鎖;
執(zhí)行業(yè)務(wù)代碼,完成后,刪除對(duì)應(yīng)的子節(jié)點(diǎn)。
如果一個(gè)已經(jīng)獲得鎖的會(huì)話超時(shí)了,因?yàn)閯?chuàng)建的是臨時(shí)節(jié)點(diǎn),所以該會(huì)話對(duì)應(yīng)的臨時(shí)節(jié)點(diǎn)會(huì)被刪除,其它會(huì)話就可以獲得鎖了??梢钥吹剑琙ookeeper 分布式鎖不會(huì)出現(xiàn)數(shù)據(jù)庫的唯一索引實(shí)現(xiàn)的分布式鎖釋放鎖失敗問題。
一個(gè)節(jié)點(diǎn)未獲得鎖,只需要監(jiān)聽自己的前一個(gè)子節(jié)點(diǎn),這是因?yàn)槿绻O(jiān)聽所有的子節(jié)點(diǎn),那么任意一個(gè)子節(jié)點(diǎn)狀態(tài)改變,其它所有子節(jié)點(diǎn)都會(huì)收到通知(羊群效應(yīng)),而我們只希望它的后一個(gè)子節(jié)點(diǎn)收到通知。
指事務(wù)的操作位于不同的節(jié)點(diǎn)上,需要保證事務(wù)的 ACID 特性。
例如在下單場景下,庫存和訂單如果不在同一個(gè)節(jié)點(diǎn)上,就涉及分布式事務(wù)。
兩階段提交(Two-phase Commit,2PC),通過引入?yún)f(xié)調(diào)者(Coordinator)來協(xié)調(diào)參與者的行為,并最終決定這些參與者是否要真正執(zhí)行事務(wù)。
協(xié)調(diào)者詢問參與者事務(wù)是否執(zhí)行成功,參與者發(fā)回事務(wù)執(zhí)行結(jié)果。
如果事務(wù)在每個(gè)參與者上都執(zhí)行成功,事務(wù)協(xié)調(diào)者發(fā)送通知讓參與者提交事務(wù);否則,協(xié)調(diào)者發(fā)送通知讓參與者回滾事務(wù)。
需要注意的是,在準(zhǔn)備階段,參與者執(zhí)行了事務(wù),但是還未提交。只有在提交階段接收到協(xié)調(diào)者發(fā)來的通知后,才進(jìn)行提交或者回滾。
所有事務(wù)參與者在等待其它參與者響應(yīng)的時(shí)候都處于同步阻塞狀態(tài),無法進(jìn)行其它操作。
協(xié)調(diào)者在 2PC 中起到非常大的作用,發(fā)生故障將會(huì)造成很大影響。特別是在階段二發(fā)生故障,所有參與者會(huì)一直等待,無法完成其它操作。
在階段二,如果協(xié)調(diào)者只發(fā)送了部分 Commit 消息,此時(shí)網(wǎng)絡(luò)發(fā)生異常,那么只有部分參與者接收到 Commit 消息,也就是說只有部分參與者提交了事務(wù),使得系統(tǒng)數(shù)據(jù)不一致。
任意一個(gè)節(jié)點(diǎn)失敗就會(huì)導(dǎo)致整個(gè)事務(wù)失敗,沒有完善的容錯(cuò)機(jī)制。
本地消息表與業(yè)務(wù)數(shù)據(jù)表處于同一個(gè)數(shù)據(jù)庫中,這樣就能利用本地事務(wù)來保證在對(duì)這兩個(gè)表的操作滿足事務(wù)特性,并且使用了消息隊(duì)列來保證最終一致性。
在分布式事務(wù)操作的一方完成寫業(yè)務(wù)數(shù)據(jù)的操作之后向本地消息表發(fā)送一個(gè)消息,本地事務(wù)能保證這個(gè)消息一定會(huì)被寫入本地消息表中。
之后將本地消息表中的消息轉(zhuǎn)發(fā)到消息隊(duì)列中,如果轉(zhuǎn)發(fā)成功則將消息從本地消息表中刪除,否則繼續(xù)重新轉(zhuǎn)發(fā)。
在分布式事務(wù)操作的另一方從消息隊(duì)列中讀取一個(gè)消息,并執(zhí)行消息中的操作。
分布式系統(tǒng)不可能同時(shí)滿足一致性(C:Consistency)、可用性(A:Availability)和分區(qū)容忍性(P:Partition Tolerance),最多只能同時(shí)滿足其中兩項(xiàng)。
一致性指的是多個(gè)數(shù)據(jù)副本是否能保持一致的特性,在一致性的條件下,系統(tǒng)在執(zhí)行數(shù)據(jù)更新操作之后能夠從一致性狀態(tài)轉(zhuǎn)移到另一個(gè)一致性狀態(tài)。
對(duì)系統(tǒng)的一個(gè)數(shù)據(jù)更新成功之后,如果所有用戶都能夠讀取到最新的值,該系統(tǒng)就被認(rèn)為具有強(qiáng)一致性。
可用性指分布式系統(tǒng)在面對(duì)各種異常時(shí)可以提供正常服務(wù)的能力,可以用系統(tǒng)可用時(shí)間占總時(shí)間的比值來衡量,4 個(gè) 9 的可用性表示系統(tǒng) 99.99% 的時(shí)間是可用的。
在可用性條件下,要求系統(tǒng)提供的服務(wù)一直處于可用的狀態(tài),對(duì)于用戶的每一個(gè)操作請(qǐng)求總是能夠在有限的時(shí)間內(nèi)返回結(jié)果。
網(wǎng)絡(luò)分區(qū)指分布式系統(tǒng)中的節(jié)點(diǎn)被劃分為多個(gè)區(qū)域,每個(gè)區(qū)域內(nèi)部可以通信,但是區(qū)域之間無法通信。
在分區(qū)容忍性條件下,分布式系統(tǒng)在遇到任何網(wǎng)絡(luò)分區(qū)故障的時(shí)候,仍然需要能對(duì)外提供一致性和可用性的服務(wù),除非是整個(gè)網(wǎng)絡(luò)環(huán)境都發(fā)生了故障。
在分布式系統(tǒng)中,分區(qū)容忍性必不可少,因?yàn)樾枰偸羌僭O(shè)網(wǎng)絡(luò)是不可靠的。因此,CAP 理論實(shí)際上是要在可用性和一致性之間做權(quán)衡。
可用性和一致性往往是沖突的,很難使它們同時(shí)滿足。在多個(gè)節(jié)點(diǎn)之間進(jìn)行數(shù)據(jù)同步時(shí),
為了保證一致性(CP),不能訪問未同步完成的節(jié)點(diǎn),也就失去了部分可用性;
為了保證可用性(AP),允許讀取所有節(jié)點(diǎn)的數(shù)據(jù),但是數(shù)據(jù)可能不一致。
BASE 是基本可用(Basically Available)、軟狀態(tài)(Soft State)和最終一致性(Eventually Consistent)三個(gè)短語的縮寫。
BASE 理論是對(duì) CAP 中一致性和可用性權(quán)衡的結(jié)果,它的核心思想是:即使無法做到強(qiáng)一致性,但每個(gè)應(yīng)用都可以根據(jù)自身業(yè)務(wù)特點(diǎn),采用適當(dāng)?shù)姆绞絹硎瓜到y(tǒng)達(dá)到最終一致性。
指分布式系統(tǒng)在出現(xiàn)故障的時(shí)候,保證核心可用,允許損失部分可用性。
例如,電商在做促銷時(shí),為了保證購物系統(tǒng)的穩(wěn)定性,部分消費(fèi)者可能會(huì)被引導(dǎo)到一個(gè)降級(jí)的頁面。
指允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認(rèn)為該中間狀態(tài)不會(huì)影響系統(tǒng)整體可用性,即允許系統(tǒng)不同節(jié)點(diǎn)的數(shù)據(jù)副本之間進(jìn)行同步的過程存在時(shí)延。
最終一致性強(qiáng)調(diào)的是系統(tǒng)中所有的數(shù)據(jù)副本,在經(jīng)過一段時(shí)間的同步后,最終能達(dá)到一致的狀態(tài)。
ACID 要求強(qiáng)一致性,通常運(yùn)用在傳統(tǒng)的數(shù)據(jù)庫系統(tǒng)上。而 BASE 要求最終一致性,通過犧牲強(qiáng)一致性來達(dá)到可用性,通常運(yùn)用在大型分布式系統(tǒng)中。
在實(shí)際的分布式場景中,不同業(yè)務(wù)單元和組件對(duì)一致性的要求是不同的,因此 ACID 和 BASE 往往會(huì)結(jié)合在一起使用。
用于達(dá)成共識(shí)性問題,即對(duì)多個(gè)節(jié)點(diǎn)產(chǎn)生的值,該算法能保證只選出唯一一個(gè)值。
主要有三類節(jié)點(diǎn):
提議者(Proposer):提議一個(gè)值;
接受者(Acceptor):對(duì)每個(gè)提議進(jìn)行投票;
告知者(Learner):被告知投票的結(jié)果,不參與投票過程。
規(guī)定一個(gè)提議包含兩個(gè)字段:[n, v],其中 n 為序號(hào)(具有唯一性),v 為提議值。
下圖演示了兩個(gè) Proposer 和三個(gè) Acceptor 的系統(tǒng)中運(yùn)行該算法的初始過程,每個(gè) Proposer 都會(huì)向所有 Acceptor 發(fā)送 Prepare 請(qǐng)求。
當(dāng) Acceptor 接收到一個(gè) Prepare 請(qǐng)求,包含的提議為 [n1, v1],并且之前還未接收過 Prepare 請(qǐng)求,那么發(fā)送一個(gè) Prepare 響應(yīng),設(shè)置當(dāng)前接收到的提議為 [n1, v1],并且保證以后不會(huì)再接受序號(hào)小于 n1 的提議。
如下圖,Acceptor X 在收到 [n=2, v=8] 的 Prepare 請(qǐng)求時(shí),由于之前沒有接收過提議,因此就發(fā)送一個(gè) [no previous] 的 Prepare 響應(yīng),設(shè)置當(dāng)前接收到的提議為 [n=2, v=8],并且保證以后不會(huì)再接受序號(hào)小于 2 的提議。其它的 Acceptor 類似。
如果 Acceptor 接收到一個(gè) Prepare 請(qǐng)求,包含的提議為 [n2, v2],并且之前已經(jīng)接收過提議 [n1, v1]。如果 n1 > n2,那么就丟棄該提議請(qǐng)求;否則,發(fā)送 Prepare 響應(yīng),該 Prepare 響應(yīng)包含之前已經(jīng)接收過的提議 [n1, v1],設(shè)置當(dāng)前接收到的提議為 [n2, v2],并且保證以后不會(huì)再接受序號(hào)小于 n2 的提議。
如下圖,Acceptor Z 收到 Proposer A 發(fā)來的 [n=2, v=8] 的 Prepare 請(qǐng)求,由于之前已經(jīng)接收過 [n=4, v=5] 的提議,并且 n > 2,因此就拋棄該提議請(qǐng)求;Acceptor X 收到 Proposer B 發(fā)來的 [n=4, v=5] 的 Prepare 請(qǐng)求,因?yàn)橹敖邮盏降奶嶙h為 [n=2, v=8],并且 2 <= 4,因此就發(fā)送 [n=2, v=8] 的 Prepare 響應(yīng),設(shè)置當(dāng)前接收到的提議為 [n=4, v=5],并且保證以后不會(huì)再接受序號(hào)小于 4 的提議。Acceptor Y 類似。
當(dāng)一個(gè) Proposer 接收到超過一半 Acceptor 的 Prepare 響應(yīng)時(shí),就可以發(fā)送 Accept 請(qǐng)求。
Proposer A 接收到兩個(gè) Prepare 響應(yīng)之后,就發(fā)送 [n=2, v=8] Accept 請(qǐng)求。該 Accept 請(qǐng)求會(huì)被所有 Acceptor 丟棄,因?yàn)榇藭r(shí)所有 Acceptor 都保證不接受序號(hào)小于 4 的提議。
Proposer B 過后也收到了兩個(gè) Prepare 響應(yīng),因此也開始發(fā)送 Accept 請(qǐng)求。需要注意的是,Accept 請(qǐng)求的 v 需要取它收到的最大提議編號(hào)對(duì)應(yīng)的 v 值,也就是 8。因此它發(fā)送 [n=4, v=8] 的 Accept 請(qǐng)求。
Acceptor 接收到 Accept 請(qǐng)求時(shí),如果序號(hào)大于等于該 Acceptor 承諾的最小序號(hào),那么就發(fā)送 Learn 提議給所有的 Learner。當(dāng) Learner 發(fā)現(xiàn)有大多數(shù)的 Acceptor 接收了某個(gè)提議,那么該提議的提議值就被 Paxos 選擇出來。
指只有一個(gè)提議值會(huì)生效。
因?yàn)?Paxos 協(xié)議要求每個(gè)生效的提議被多數(shù) Acceptor 接收,并且 Acceptor 不會(huì)接受兩個(gè)不同的提議,因此可以保證正確性。
指最后總會(huì)有一個(gè)提議生效。
Paxos 協(xié)議能夠讓 Proposer 發(fā)送的提議朝著能被大多數(shù) Acceptor 接受的那個(gè)提議靠攏,因此能夠保證可終止性。
Raft 也是分布式一致性協(xié)議,主要是用來競選主節(jié)點(diǎn)。
有三種節(jié)點(diǎn):Follower、Candidate 和 Leader。Leader 會(huì)周期性的發(fā)送心跳包給 Follower。每個(gè) Follower 都設(shè)置了一個(gè)隨機(jī)的競選超時(shí)時(shí)間,一般為 150ms~300ms,如果在這個(gè)時(shí)間內(nèi)沒有收到 Leader 的心跳包,就會(huì)變成 Candidate,進(jìn)入競選階段。
下圖展示一個(gè)分布式系統(tǒng)的最初階段,此時(shí)只有 Follower 沒有 Leader。Node A 等待一個(gè)隨機(jī)的競選超時(shí)時(shí)間之后,沒收到 Leader 發(fā)來的心跳包,因此進(jìn)入競選階段。
此時(shí) Node A 發(fā)送投票請(qǐng)求給其它所有節(jié)點(diǎn)。
其它節(jié)點(diǎn)會(huì)對(duì)請(qǐng)求進(jìn)行回復(fù),如果超過一半的節(jié)點(diǎn)回復(fù)了,那么該 Candidate 就會(huì)變成 Leader。
之后 Leader 會(huì)周期性地發(fā)送心跳包給 Follower,F(xiàn)ollower 接收到心跳包,會(huì)重新開始計(jì)時(shí)。
如果有多個(gè) Follower 成為 Candidate,并且所獲得票數(shù)相同,那么就需要重新開始投票。例如下圖中 Node B 和 Node D 都獲得兩票,需要重新開始投票。
由于每個(gè)節(jié)點(diǎn)設(shè)置的隨機(jī)競選超時(shí)時(shí)間不同,因此下一次再次出現(xiàn)多個(gè) Candidate 并獲得同樣票數(shù)的概率很低。
來自客戶端的修改都會(huì)被傳入 Leader。注意該修改還未被提交,只是寫入日志中。
Leader 會(huì)把修改復(fù)制到所有 Follower。
Leader 會(huì)等待大多數(shù)的 Follower 也進(jìn)行了修改,然后才將修改提交。
此時(shí) Leader 會(huì)通知的所有 Follower 讓它們也提交修改,此時(shí)所有節(jié)點(diǎn)的值達(dá)成一致。
本文名稱:關(guān)于分布式,你需要知道的真相
URL地址:http://jinyejixie.com/article10/ggegdo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、云服務(wù)器、ChatGPT、動(dòng)態(tài)網(wǎng)站、網(wǎng)站改版、網(wǎng)頁設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)