1 Paxos算法
算法中的參與者主要分為三個(gè)角色砸琅,同時(shí)每個(gè)參與者又可兼領(lǐng)多個(gè)角色:
⑴proposer提出提案迫摔,提案信息包括提案編號(hào)和提議的value;
⑵acceptor收到提案后可以接受(accept)提案;
⑶learner只能"學(xué)習(xí)"被批準(zhǔn)的提案;
算法保重一致性的基本語(yǔ)義:
⑴決議(value)只有在被proposers提出后才能被批準(zhǔn)(未經(jīng)批準(zhǔn)的決議稱為"提案(proposal)");
⑵在一次Paxos算法的執(zhí)行實(shí)例中,只批準(zhǔn)(chosen)一個(gè)value;
⑶learners只能獲得被批準(zhǔn)(chosen)的value;
有上面的三個(gè)語(yǔ)義可演化為四個(gè)約束:
⑴P1:一個(gè)acceptor必須接受(accept)第一次收到的提案;
⑵P2a:一旦一個(gè)具有value?v的提案被批準(zhǔn)(chosen)汤踏,那么之后任何acceptor再次接受(accept)的提案必須具有value?v;
⑶P2b:一旦一個(gè)具有value?v的提案被批準(zhǔn)(chosen)织鲸,那么以后任何proposer提出的提案必須具有value?v;
⑷P2c:如果一個(gè)編號(hào)為n的提案具有value?v,那么存在一個(gè)多數(shù)派溪胶,要么他們中所有人都沒(méi)有接受(accept)編號(hào)小于n的任何提案搂擦,要么他們已經(jīng)接受(accpet)的所有編號(hào)小于n的提案中編號(hào)最大的那個(gè)提案具有value?v;
算法(決議的提出與批準(zhǔn))主要分為兩個(gè)階段:
1.prepare階段:
(1).當(dāng)Porposer希望提出方案V1,首先發(fā)出prepare請(qǐng)求至大多數(shù)Acceptor哗脖。Prepare請(qǐng)求內(nèi)容為序列號(hào);
(2).當(dāng)Acceptor接收到prepare請(qǐng)求時(shí)盾饮,檢查自身上次回復(fù)過(guò)的prepare請(qǐng)求
a).如果SN2>SN1,則忽略此請(qǐng)求,直接結(jié)束本次批準(zhǔn)過(guò)程;
b).否則檢查上次批準(zhǔn)的accept請(qǐng)求丘损,并且回復(fù)普办;如果之前沒(méi)有進(jìn)行過(guò)批準(zhǔn),則簡(jiǎn)單回復(fù);
2.?accept批準(zhǔn)階段:
(1a).經(jīng)過(guò)一段時(shí)間徘钥,收到一些Acceptor回復(fù)衔蹲,回復(fù)可分為以下幾種:
a).回復(fù)數(shù)量滿足多數(shù)派,并且所有的回復(fù)都是呈础,則Porposer發(fā)出accept請(qǐng)求舆驶,請(qǐng)求內(nèi)容為議案;
b).回復(fù)數(shù)量滿足多數(shù)派,但有的回復(fù)為:而钞,……則Porposer找到所有回復(fù)中超過(guò)半數(shù)的那個(gè)沙廉,假設(shè)為,則發(fā)出accept請(qǐng)求臼节,請(qǐng)求內(nèi)容為議案;
c).回復(fù)數(shù)量不滿足多數(shù)派撬陵,Proposer嘗試增加序列號(hào)為SN1+,轉(zhuǎn)1繼續(xù)執(zhí)行;
(1b).經(jīng)過(guò)一段時(shí)間网缝,收到一些Acceptor回復(fù)巨税,回復(fù)可分為以下幾種:
a).回復(fù)數(shù)量滿足多數(shù)派,則確認(rèn)V1被接受;
b).回復(fù)數(shù)量不滿足多數(shù)派粉臊,V1未被接受草添,Proposer增加序列號(hào)為SN1+,轉(zhuǎn)1繼續(xù)執(zhí)行;
(2).在不違背自己向其他proposer的承諾的前提下扼仲,acceptor收到accept請(qǐng)求后即接受并回復(fù)這個(gè)請(qǐng)求远寸。
Paxos算法在出現(xiàn)競(jìng)爭(zhēng)的情況下,其收斂速度很慢屠凶,甚至可能出現(xiàn)活鎖的情況而晒,例如當(dāng)有三個(gè)及三個(gè)以上的proposer在發(fā)送prepare請(qǐng)求后,很難有一個(gè)proposer收到半數(shù)以上的回復(fù)而不斷地執(zhí)行第一階段的協(xié)議阅畴。因此倡怎,為了避免競(jìng)爭(zhēng),加快收斂的速度贱枣,在算法中引入了一個(gè)Leader這個(gè)角色监署,在正常情況下同時(shí)應(yīng)該最多只能有一個(gè)參與者扮演Leader角色,而其它的參與者則扮演Acceptor的角色纽哥,同時(shí)所有的人又都扮演Learner的角色钠乏。
在這種優(yōu)化算法中,只有Leader可以提出議案春塌,從而避免了競(jìng)爭(zhēng)使得算法能夠快速地收斂而趨于一致晓避,此時(shí)的paxos算法在本質(zhì)上就退變?yōu)閮呻A段提交協(xié)議簇捍。但在異常情況下,系統(tǒng)可能會(huì)出現(xiàn)多Leader的情況俏拱,但這并不會(huì)破壞算法對(duì)一致性的保證暑塑,此時(shí)多個(gè)Leader都可以提出自己的提案,優(yōu)化的算法就退化成了原始的paxos算法锅必。
一個(gè)Leader的工作流程主要有分為三個(gè)階段:
(1).學(xué)習(xí)階段?向其它的參與者學(xué)習(xí)自己不知道的數(shù)據(jù)(決議);
(2).同步階段?讓絕大多數(shù)參與者保持?jǐn)?shù)據(jù)(決議)的一致性;
(3).服務(wù)階段?為客戶端服務(wù)事格,提議案;
當(dāng)一個(gè)參與者成為了Leader之后,它應(yīng)該需要知道絕大多數(shù)的paxos實(shí)例搞隐,因此就會(huì)馬上啟動(dòng)一個(gè)主動(dòng)學(xué)習(xí)的過(guò)程驹愚。假設(shè)當(dāng)前的新Leader早就知道了1-134、138和139的paxos實(shí)例劣纲,那么它會(huì)執(zhí)行135-137和大于139的paxos實(shí)例的第一階段逢捺。如果只檢測(cè)到135和140的paxos實(shí)例有確定的值,那它最后就會(huì)知道1-135以及138-140的paxos實(shí)例癞季。
此時(shí)的Leader已經(jīng)知道了1-135劫瞳、138-140的paxos實(shí)例,那么它就會(huì)重新執(zhí)行1-135的paxos實(shí)例余佛,以保證絕大多數(shù)參與者在1-135的paxos實(shí)例上是保持一致的。至于139-140的paxos實(shí)例窍荧,它并不馬上執(zhí)行138-140的paxos實(shí)例辉巡,而是等到在服務(wù)階段填充了136、137的paxos實(shí)例之后再執(zhí)行蕊退。這里之所以要填充間隔郊楣,是為了避免以后的Leader總是要學(xué)習(xí)這些間隔中的paxos實(shí)例,而這些paxos實(shí)例又沒(méi)有對(duì)應(yīng)的確定值瓤荔。
Leader將用戶的請(qǐng)求轉(zhuǎn)化為對(duì)應(yīng)的paxos實(shí)例净蚤,當(dāng)然,它可以并發(fā)的執(zhí)行多個(gè)paxos實(shí)例输硝,當(dāng)這個(gè)Leader出現(xiàn)異常之后今瀑,就很有可能造成paxos實(shí)例出現(xiàn)間斷。
(1).Leader的選舉原則
(2).Acceptor如何感知當(dāng)前Leader的失敗点把,客戶如何知道當(dāng)前的Leader
(3).當(dāng)出現(xiàn)多Leader之后橘荠,如何kill掉多余的Leader
(4).如何動(dòng)態(tài)的擴(kuò)展Acceptor
在Zookeeper集群中,主要分為三者角色郎逃,而每一個(gè)節(jié)點(diǎn)同時(shí)只能扮演一種角色哥童,這三種角色分別是:
(1).?Leader?接受所有Follower的提案請(qǐng)求并統(tǒng)一協(xié)調(diào)發(fā)起提案的投票,負(fù)責(zé)與所有的Follower進(jìn)行內(nèi)部的數(shù)據(jù)交換(同步);
(2).?Follower?直接為客戶端服務(wù)并參與提案的投票褒翰,同時(shí)與Leader進(jìn)行數(shù)據(jù)交換(同步);
(3).?Observer?直接為客戶端服務(wù)但并不參與提案的投票贮懈,同時(shí)也與Leader進(jìn)行數(shù)據(jù)交換(同步);
Zookeeper對(duì)于每個(gè)節(jié)點(diǎn)QuorumPeer的設(shè)計(jì)相當(dāng)?shù)撵`活匀泊,QuorumPeer主要包括四個(gè)組件:客戶端請(qǐng)求接收器(ServerCnxnFactory)、數(shù)據(jù)引擎(ZKDatabase)朵你、選舉器(Election)各聘、核心功能組件(Leader/Follower/Observer)。其中:
(1).ServerCnxnFactory負(fù)責(zé)維護(hù)與客戶端的連接(接收客戶端的請(qǐng)求并發(fā)送相應(yīng)的響應(yīng));
(2).ZKDatabase負(fù)責(zé)存儲(chǔ)/加載/查找數(shù)據(jù)(基于目錄樹(shù)結(jié)構(gòu)的KV+操作日志+客戶端Session);
(3).Election負(fù)責(zé)選舉集群的一個(gè)Leader節(jié)點(diǎn);
(4).Leader/Follower/Observer一個(gè)QuorumPeer節(jié)點(diǎn)應(yīng)該完成的核心職責(zé);
Follower確認(rèn):等待所有的Follower連接注冊(cè)撬呢,若在規(guī)定的時(shí)間內(nèi)收到合法的Follower注冊(cè)數(shù)量伦吠,則確認(rèn)成功;否則魂拦,確認(rèn)失敗毛仪。
選舉線程由當(dāng)前Server發(fā)起選舉的線程擔(dān)任,他主要的功能對(duì)投票結(jié)果進(jìn)行統(tǒng)計(jì)芯勘,并選出推薦的Server箱靴。選舉線程首先向所有Server發(fā)起一次詢問(wèn)(包括自己),被詢問(wèn)方荷愕,根據(jù)自己當(dāng)前的狀態(tài)作相應(yīng)的回復(fù)衡怀,選舉線程收到回復(fù)后,驗(yàn)證是否是自己發(fā)起的詢問(wèn)(驗(yàn)證xid是否一致)安疗,然后獲取對(duì)方的id(myid)抛杨,并存儲(chǔ)到當(dāng)前詢問(wèn)對(duì)象列表中,最后獲取對(duì)方提議?的
leader相關(guān)信息(id,zxid)荐类,并將這些?信息存儲(chǔ)到當(dāng)次選舉的投票記錄表中怖现,當(dāng)向所有Serve?r
都詢問(wèn)完以后,對(duì)統(tǒng)計(jì)結(jié)果進(jìn)行篩選并進(jìn)行統(tǒng)計(jì)玉罐,計(jì)算出當(dāng)次詢問(wèn)后獲勝的是哪一個(gè)Server屈嗤,并將當(dāng)前zxid最大的Server設(shè)置為當(dāng)前Server要推薦的Server(有可能是自己,也有可以是其它的Server吊输,根據(jù)投票結(jié)果而定饶号,但是每一個(gè)Server在第一次投票時(shí)都會(huì)投自己),如果此時(shí)獲勝的Server獲得n/2?+?1的Server票數(shù)季蚂,設(shè)置當(dāng)前推薦的leader為獲勝的Server茫船。根據(jù)獲勝的Server相關(guān)信息設(shè)置自己的狀態(tài)。每一個(gè)Server都重復(fù)以上流程直到選舉出Leader扭屁。
初始化選票(第一張選票):每個(gè)quorum節(jié)點(diǎn)一開(kāi)始都投給自己;
收集選票:使用UDP協(xié)議盡量收集所有quorum節(jié)點(diǎn)當(dāng)前的選票(單線程/同步方式)透硝,超時(shí)設(shè)置200ms;
統(tǒng)計(jì)選票:?1).每個(gè)quorum節(jié)點(diǎn)的票數(shù);
2).為自己產(chǎn)生一張新選票(zxid、myid均最大);
選舉成功:某一個(gè)quorum節(jié)點(diǎn)的票數(shù)超過(guò)半數(shù);
更新選票:在本輪選舉失敗的情況下疯搅,當(dāng)前quorum節(jié)點(diǎn)會(huì)從收集的選票中選取合適的選票(zxid濒生、myid均最大)作為自己下一輪選舉的投票;
異常問(wèn)題的處理
1).?選舉過(guò)程中,Server的加入
當(dāng)一個(gè)Server啟動(dòng)時(shí)它都會(huì)發(fā)起一次選舉幔欧,此時(shí)由選舉線程發(fā)起相關(guān)流程罪治,那么每個(gè)Serve?r都會(huì)獲得當(dāng)前zxi?d最大的哪個(gè)Serve?r是誰(shuí)丽声,如果當(dāng)次最大的Serve?r沒(méi)有獲得n/2+1個(gè)票數(shù),那么下一次投票時(shí)觉义,他將向zxid最大的Server投票雁社,重復(fù)以上流程,最后一定能選舉出一個(gè)Leader晒骇。
2).?選舉過(guò)程中霉撵,Server的退出
只要保證n/2+1個(gè)Server存活就沒(méi)有任何問(wèn)題,如果少于n/2+1個(gè)Server存活就沒(méi)辦法選出Leader洪囤。
3).?選舉過(guò)程中徒坡,Leader死亡
當(dāng)選舉出Leader以后,此時(shí)每個(gè)Server應(yīng)該是什么狀態(tài)(FLLOWING)都已經(jīng)確定瘤缩,此時(shí)由于Leader已經(jīng)死亡我們就不管它喇完,其它的Fllower按正常的流程繼續(xù)下去,當(dāng)完成這個(gè)流程以后剥啤,所有的Fllower都會(huì)向Leader發(fā)送Ping消息锦溪,如果無(wú)法ping通,就改變自己的狀為(FLLOWING?==>?LOOKING)府怯,發(fā)起新的一輪選舉刻诊。
4).?選舉完成以后,Leader死亡
處理過(guò)程同上牺丙。
5).?雙主問(wèn)題
Leader的選舉是保證只產(chǎn)生一個(gè)公認(rèn)的Leader的则涯,而且Follower重新選舉與舊Leader恢復(fù)并退出基本上是同時(shí)發(fā)生的,當(dāng)Follower無(wú)法ping同Leader是就認(rèn)為L(zhǎng)eader已經(jīng)出問(wèn)題開(kāi)始重新選舉赘被,Leader收到Follower的ping沒(méi)有達(dá)到半數(shù)以上則要退出Leader重新選舉是整。
FastLeaderElection是標(biāo)準(zhǔn)的fast?paxos的實(shí)現(xiàn)肖揣,它首先向所有Server提議自己要成為leader,當(dāng)其它Server收到提議以后,解決epoch和zxid的沖突算色,并接受對(duì)方的提議浇借,然后向?qū)Ψ桨l(fā)送接受提議完成的消息。
FastLeaderElection算法通過(guò)異步的通信方式來(lái)收集其它節(jié)點(diǎn)的選票彤断,同時(shí)在分析選票時(shí)又根據(jù)投票者的當(dāng)前狀態(tài)來(lái)作不同的處理野舶,以加快Leader的選舉進(jìn)程。
每個(gè)Server都一個(gè)接收線程池和一個(gè)發(fā)送線程池,在沒(méi)有發(fā)起選舉時(shí)宰衙,這兩個(gè)線程池處于阻塞狀態(tài)平道,直到有消息到來(lái)時(shí)才解除阻塞并處理消息,同時(shí)每個(gè)Serve?r都有一個(gè)選舉線程(可以發(fā)起選舉的線程擔(dān)任)供炼。
1).?主動(dòng)發(fā)起選舉端(選舉線程)的處理
首先自己的logicalclock加1一屋,然后生成notification消息窘疮,并將消息放入發(fā)送隊(duì)列中,?系統(tǒng)中配置有幾個(gè)Server就生成幾條消息冀墨,保證每個(gè)Server都能收到此消息闸衫,如果當(dāng)前Server的狀態(tài)是LOOKING就一直循環(huán)檢查接收隊(duì)列是否有消息,如果有消息诽嘉,根據(jù)消息中對(duì)方的狀態(tài)進(jìn)行相應(yīng)的處理蔚出。
2).主動(dòng)發(fā)送消息端(發(fā)送線程池)的處理
將要發(fā)送的消息由Notification消息轉(zhuǎn)換成ToSend消息,然后發(fā)送對(duì)方虫腋,并等待對(duì)方的回復(fù)骄酗。
3).?被動(dòng)接收消息端(接收線程池)的處理
將收到的消息轉(zhuǎn)換成Notification消息放入接收隊(duì)列中,如果對(duì)方Server的epoch小于logicalclock則向其發(fā)送一個(gè)消息(讓其更新epoch)岔乔;如果對(duì)方Server處于Looking狀態(tài)酥筝,自己則處于Following或Leading狀態(tài),則也發(fā)送一個(gè)消息(當(dāng)前Leader已產(chǎn)生雏门,讓其盡快收斂)嘿歌。
2.4.3?AuthFastLeaderElection選舉算法
AuthFastLeaderElection算法同F(xiàn)astLeaderElection算法基本一致,只是在消息中加入了認(rèn)證信息茁影,該算法在最新的Zookeeper中也建議棄用宙帝。
名稱
同步
異步
watch
權(quán)限認(rèn)證
create
√
√
√
delete
√
√
√
exist
√
√
√
getData
√
√
√
√
setData
√
√
√
getACL
√
√
setACL
√
√
√
getChildren
√
√
√
√
sync
√
multi
√
√
createSession
√
closeSession
√
2.6.1?Follower節(jié)點(diǎn)處理用戶的讀寫(xiě)請(qǐng)求
2.6.2?Leader節(jié)點(diǎn)處理寫(xiě)請(qǐng)求
值得注意的是, Follower/Leader上的讀操作時(shí)并行的募闲,讀寫(xiě)操作是串行的步脓,當(dāng)CommitRequestProcessor處理一個(gè)寫(xiě)請(qǐng)求時(shí),會(huì)阻塞之后所有的讀寫(xiě)請(qǐng)求浩螺。