1蛤高、Zookeeper總體架構
應用使用Zookeeper客戶端庫使用Zookeeper服務证芭。Zookeeper客戶端負責和Zookeeper的集群交互。
Zookeeper集群可以有兩種模式:standalone模式和quorum模式。
處于standalone模式的Zookeeper集群中只有一個獨立運行的Zookeeper節(jié)點餐禁。
處于quorum模式的Zookeeper集群中包含多個Zookeeper節(jié)點诗祸。
2跑芳、session
Zookeeper客戶端庫和Zookeeper集群中的節(jié)點創(chuàng)建一個session。
客戶端可以主動關閉session直颅。
如果Zookeeper節(jié)點沒有在session關聯(lián)的timeout時間內(nèi)收到客戶端的數(shù)據(jù)的話博个,Zookeeper節(jié)點也會關閉session。
另外Zookeeper客戶端庫如果發(fā)現(xiàn)連接的Zookeeper出錯功偿,會自動和其他Zookeeper的節(jié)點建立連接坡倔。
3、Quorum模式
處于Quorum模式的Zookeeper集群包含多個Zookeeper節(jié)點脖含。例如下圖的Zookeeper集群有三個節(jié)點罪塔,其中節(jié)點1是leader節(jié)點,節(jié)點2和節(jié)點3是follower節(jié)點养葵。
leader節(jié)點可以處理讀寫請求征堪,follower節(jié)點只可以處理讀請求。fllower在接到寫請求時會把寫請求轉發(fā)給leader來處理关拒。
4佃蚜、數(shù)據(jù)一致性
- 可線性化(Linearizable)寫入:先到達leader的寫請求會被先處理,leader決定寫請求的執(zhí)行順序着绊。
- 客戶端FIFO順序:來自給定客戶端的請求按照發(fā)送順序執(zhí)行谐算。
5、底層分布式選舉算法
ZAB(ZooKeeper Atomic Broadcast)選舉算法是為 ZooKeeper 實現(xiàn)分布式協(xié)調(diào)功能而設計的归露。相較于 Raft 算法的投票機制洲脂,ZAB 算法增加了通過節(jié)點 ID 和數(shù)據(jù) ID 作為參考進行選主,節(jié)點 ID 和數(shù)據(jù) ID 越大剧包,表示數(shù)據(jù)越新恐锦,優(yōu)先成為主。相比較于 Raft 算法疆液,ZAB 算法盡可能保證數(shù)據(jù)的最新性一铅。所以,ZAB 算法可以說是對 Raft 算法的改進堕油。使用 ZAB 算法選舉時潘飘,集群中每個節(jié)點擁有 3 種角色:
Leader肮之,主節(jié)點;
Follower卜录,跟隨者節(jié)點局骤;
Observer,觀察者暴凑,無投票權峦甩。
選舉過程中,集群中的節(jié)點擁有 4 個狀態(tài):
Looking 狀態(tài)现喳,即選舉狀態(tài)凯傲。當節(jié)點處于該狀態(tài)時,它會認為當前集群中沒有 Leader嗦篱,因此自己進入選舉狀態(tài)冰单。
Leading 狀態(tài),即領導者狀態(tài)灸促,表示已經(jīng)選出主诫欠,且當前節(jié)點為 Leader。
Following 狀態(tài)浴栽,即跟隨者狀態(tài)荒叼,集群中已經(jīng)選出主后,其他非主節(jié)點狀態(tài)更新為 Following典鸡,表示對 Leader 的追隨被廓。
Observing 狀態(tài) ,即觀察者狀態(tài)萝玷,表示當前節(jié)點為 Observer嫁乘,持觀望態(tài)度,沒有投票權和選舉權球碉。
投票過程中蜓斧,每個節(jié)點都有一個唯一的三元組 (server_id, server_zxID, epoch),其中 server_id 表示本節(jié)點的唯一 ID睁冬;server_zxID 表示本節(jié)點存放的數(shù)據(jù) ID挎春,數(shù)據(jù) ID 越大表示數(shù)據(jù)越新,選舉權重越大痴突;epoch 表示當前選取輪數(shù)搂蜓,一般用邏輯時鐘表示狼荞。
ZAB 選舉算法的核心是“少數(shù)服從多數(shù)辽装,ID 大的節(jié)點優(yōu)先成為主”,因此選舉過程中通過 (vote_id, vote_zxID) 來表明投票給哪個節(jié)點相味,其中 vote_id 表示被投票節(jié)點的 ID拾积,vote_zxID 表示被投票節(jié)點的服務器 zxID。ZAB 算法選主的原則是:server_zxID 最大者成為 Leader;若 server_zxID 相同拓巧,則 server_id 最大者成為 Leader斯碌。
接下來,以 3 個 Server 的集群為例肛度,此處每個 Server 代表一個節(jié)點傻唾,介紹 ZAB 選主的過程。
第一步:當系統(tǒng)剛啟動時承耿,3 個服務器當前投票均為第一輪投票冠骄,即 epoch=1,且 zxID 均為 0加袋。此時每個服務器都推選自己凛辣,并將選票信息 <epoch, vote_id, vote_zxID> 廣播出去。
第二步:根據(jù)判斷規(guī)則职烧,由于 3 個 Server 的 epoch扁誓、zxID 都相同,因此比較 server_id蚀之,較大者即為推選對象蝗敢,因此 Server 1 和 Server 2 將 vote_id 改為 3,更新自己的投票箱并重新廣播自己的投票足删。
第三步:此時系統(tǒng)內(nèi)所有服務器都推選了 Server 3前普,因此 Server 3 當選 Leader,處于 Leading 狀態(tài)壹堰,向其他服務器發(fā)送心跳包并維護連接拭卿;Server1 和 Server2 處于 Following 狀態(tài)。
總結:
ZAB 算法性能高贱纠,對系統(tǒng)無特殊要求峻厚,采用廣播方式發(fā)送信息,若節(jié)點中有 n 個節(jié)點谆焊,每個節(jié)點同時廣播惠桃,則集群中信息量為 n*(n-1) 個消息,容易出現(xiàn)廣播風暴辖试;且除了投票辜王,還增加了對比節(jié)點 ID 和數(shù)據(jù) ID,這就意味著還需要知道所有節(jié)點的 ID 和數(shù)據(jù) ID罐孝,所以選舉時間相對較長呐馆。但該算法選舉穩(wěn)定性比較好,當有新節(jié)點加入或節(jié)點故障恢復后莲兢,會觸發(fā)選主汹来,但不一定會真正切主续膳,除非新節(jié)點或故障后恢復的節(jié)點數(shù)據(jù) ID 和節(jié)點 ID 最大,且獲得投票數(shù)過半收班,才會導致切主坟岔。
6、三個節(jié)點quorum模式Zookeeper集群(偽集群)構建
1)準備三個配置文件摔桦,其中dataDir和clientPort配置項要配置不同的值社付。三個配置文件的server.n部分都是一樣的。同時在每個節(jié)點的dataDir目錄下邻耕,需要創(chuàng)建myid文件瘦穆,三個節(jié)點的myid文件內(nèi)容分別為1、2和3
node1節(jié)點的配置內(nèi)容:
2)通過以下命令啟動集群
zkServer.sh start-foreground /usr/local/apache-zookeeper-3.6.0-bin/conf/zoo-quorum-node1.cfg
zkServer.sh start-foreground /usr/local/apache-zookeeper-3.6.0-bin/conf/zoo-quorum-node2.cfg
zkServer.sh start-foreground /usr/local/apache-zookeeper-3.6.0-bin/conf/zoo-quorum-node3.cfg
說明:start-foreground 選項赊豌,讓zkServer.sh在前臺運行扛或,把日志直接輸出到console.如果日志輸出到日志文件的話,因為是偽集群模式碘饼,會把日志輸出到同一個文件熙兔。
-
在啟動第一個節(jié)點的時候,會報一下錯誤信息:
這是因為我們集群設置的是3個節(jié)點艾恼,在其他節(jié)點還沒有啟動的情況下住涉,它是無法跟其他節(jié)點建立連接的:
05-07啟動第一個節(jié)點.png -
啟動第二個節(jié)點,那么現(xiàn)在集群中就存在兩個節(jié)點了钠绍,并且第二個節(jié)點為leading狀態(tài)舆声,即為主節(jié)點
05-08啟動第二個節(jié)點.png
第一個節(jié)點為following狀態(tài),即跟隨者狀態(tài):
05-09第一個節(jié)點的狀態(tài).png -
啟動第三個節(jié)點柳爽,觸發(fā)選主
第二個節(jié)點是主節(jié)點:
05-10啟動第三個節(jié)點.png
第一個和第三個都是跟隨者節(jié)點:
05-11跟隨節(jié)點.png
05-12跟隨節(jié)點.png
其他說明:
啟動zookeeper失敗提示8080端口被占用媳握,這是zookeeper3.5的特性
Zookeeper AdminServer,默認使用8080端口
05-13AdminServer異常.png
解決方法:
修改zoo.cfg文件的配置磷脯,添加如下配置
admin.serverPort=8888
或者在啟動腳本中增加 -Dzookeeper.admin.serverPort=端口號.
修改后再次啟動zookeeper蛾找,查看啟動日志,啟動成功赵誓。
- 使用 zkCli客戶端進行連接
zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
根據(jù)日志打毛,說明跟第一個節(jié)點建立了連接,并且也能夠正常使用
如果此時殺掉第一個節(jié)點俩功,來查看客戶端是否能夠重連:
此時可以看到幻枉,客戶端重新連接到了第三個節(jié)點,而且也能夠正常使用: