1、系統(tǒng)模型
1.1、數(shù)據(jù)模型
Zookeeper 的視圖結(jié)構(gòu)是一個樹形結(jié)構(gòu)她君,樹上的每個節(jié)點(diǎn)稱之為數(shù)據(jù)節(jié)點(diǎn)(即 ZNode)静稻,每個ZNode 上都可以保存數(shù)據(jù)警没,同時還可以掛載子節(jié)點(diǎn)。并且Zookeeper的根節(jié)點(diǎn)為 "/"振湾。
1.2杀迹、節(jié)點(diǎn)類型
在 Zookeeper 中,每個數(shù)據(jù)節(jié)點(diǎn)都是有生命周期的押搪,其生命周期的長短取決于數(shù)據(jù)節(jié)點(diǎn)的節(jié)點(diǎn)類型树酪。在 Zookeeper 中有如下幾類節(jié)點(diǎn):
節(jié)點(diǎn)類型 | 說明 |
---|---|
持久節(jié)點(diǎn)(PERSISTENT) | 指該數(shù)據(jù)節(jié)點(diǎn)被創(chuàng)建后浅碾,就會一直存在于 Zookeeper 服務(wù)器上,直到有刪除操作來主動清除這個節(jié)點(diǎn)续语。 |
持久順序節(jié)點(diǎn)(PERSISTENT_SEQUENTIAL) | 基本特性和持久節(jié)點(diǎn)是一致的垂谢,額外的特性表現(xiàn)在順序性上,在 Zookeeper 中疮茄,每個父節(jié)點(diǎn)都會為它的第一級子節(jié)點(diǎn)維護(hù)一份順序滥朱,用于記錄下每個子節(jié)點(diǎn)創(chuàng)建的先后順序×κ裕基于這個順序特性徙邻,在創(chuàng)建子節(jié)點(diǎn)的時候,可以設(shè)置這個標(biāo)記懂版,那么在創(chuàng)建節(jié)點(diǎn)過程中鹃栽,Zookeeper 會自動為給定節(jié)點(diǎn)名加上一個數(shù)字后綴,作為一個新的躯畴、完整的節(jié)點(diǎn)名民鼓。另外需要注意的是,這個數(shù)字后綴的上限是整型的最大值蓬抄。 |
臨時節(jié)點(diǎn)(EPHEMERAL) | 臨時節(jié)點(diǎn)的生命周期和客戶端的會話綁定在一起丰嘉,如果客戶端會話失效,那么這個節(jié)點(diǎn)就會被自動清理掉嚷缭。另外饮亏,Zookeeper 規(guī)定了不能基于臨時節(jié)點(diǎn)來創(chuàng)建子節(jié)點(diǎn),即臨時節(jié)點(diǎn)只能作為葉子節(jié)點(diǎn)阅爽。 |
臨時順序節(jié)點(diǎn)(EPHEMERAL_SEQUENTIAL) | 基本特性和臨時節(jié)點(diǎn)一致路幸,只是添加了順序的特性。 |
1.3付翁、狀態(tài)信息
每個數(shù)據(jù)節(jié)點(diǎn)中除了存儲了數(shù)據(jù)內(nèi)容之外简肴,還存儲了數(shù)據(jù)節(jié)點(diǎn)本身的一些狀態(tài)信息(State)。
狀態(tài)屬性 | 說明 |
---|---|
cZxid | 即 Create ZXID百侧,表示該數(shù)據(jù)節(jié)點(diǎn)被創(chuàng)建時的事務(wù)ID砰识。 |
ctime | 即 Create Time,表示該數(shù)據(jù)節(jié)點(diǎn)被創(chuàng)建的時間佣渴。 |
mZxid | 即 Modified ZXID辫狼,表示該節(jié)點(diǎn)最后一次被更新時的事務(wù)ID。 |
mtime | 即 Modified Time辛润,表示該數(shù)據(jù)節(jié)點(diǎn)最后一次被更新的時間膨处。 |
pZxid | 表示該節(jié)點(diǎn)的子節(jié)點(diǎn)列表最后一次被修改時的事務(wù)ID。注意,只有子節(jié)點(diǎn)列表變更了才會變更 pZxid真椿,子節(jié)點(diǎn)內(nèi)容變更不會影響pZxid秦叛。 |
cversion | 表示子節(jié)點(diǎn)的版本號。 |
dataVersion | 表示數(shù)據(jù)節(jié)點(diǎn)的版本號瀑粥。 |
aclVersion | 表示節(jié)點(diǎn)的 ACL 版本號。 |
ephemeralOwner | 創(chuàng)建該臨時節(jié)點(diǎn)的會話的sessionID三圆。如果該節(jié)點(diǎn)是持久節(jié)點(diǎn)狞换,那么這個屬性值為0。 |
dataLength | 表示數(shù)據(jù)內(nèi)容的長度舟肉。 |
numChildren | 表示當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)個數(shù)修噪。 |
1.4、ZXID
在Zookeeper 中路媚,事務(wù)是指能夠改變 Zookeeper 服務(wù)器狀態(tài)的操作黄琼,我們也稱之為事務(wù)操作或更新操作,一般包括數(shù)據(jù)節(jié)點(diǎn)創(chuàng)建與刪除整慎、數(shù)據(jù)節(jié)點(diǎn)內(nèi)容更新和客戶端會話創(chuàng)建與失效等操作脏款。對于每一個事務(wù)請求,Zookeeper 都會為其分配一個全局唯一的事務(wù)ID裤园,用 ZXID 來表示撤师,通常是一個 64 位的數(shù)字。每一個 ZXID 對應(yīng)一次更新操作拧揽,從這些 ZXID 中可以間接地識別出 Zookeeper 處理這些更新操作請求的全局順序剃盾。
ZXID 是一個 64 位的數(shù)字,其中低 32 位可以看作是一個簡單的單調(diào)遞增的計(jì)數(shù)器淤袜,針對客戶端的每一個事務(wù)請求痒谴,Leader 服務(wù)器在產(chǎn)生一個新的事務(wù) Proposal 的時候,都會對該計(jì)數(shù)器進(jìn)行加 1 操作铡羡;而高 32 位則代表了 Leader 周期 epoch 的編號积蔚,每當(dāng)選舉產(chǎn)生一個新的 Leader 服務(wù)器,就會從這個 Leader 服務(wù)器上取出其本地日志中最大事務(wù) Proposal 的 ZXID蓖墅,并從該 ZXID 中解析出對應(yīng)的 epoch 值库倘,然后再對其進(jìn)行加 1 操作,之后就會以此編號作為新的 epoch论矾,并將低 32 位置 0 來開始生成新的 ZXID教翩。
1.5、版本
Zookeeper 中為數(shù)據(jù)節(jié)點(diǎn)引入了版本的概念贪壳,每個數(shù)據(jù)節(jié)點(diǎn)都具有三種類型的版本信息(在上面的狀態(tài)信息中已經(jīng)介紹了三種版本信息代表的意思)饱亿,對數(shù)據(jù)節(jié)點(diǎn)的任何更新操作都會引起版本號的變化。其中我們以 dataVersion 為例來說明。在一個數(shù)據(jù)節(jié)點(diǎn)被創(chuàng)建完畢之后彪笼,節(jié)點(diǎn)的dataVersion 值是 0钻注,表示的含義是 ”當(dāng)前節(jié)點(diǎn)自從創(chuàng)建之后,被更新過 0 次“配猫。如果現(xiàn)在對該節(jié)點(diǎn)的數(shù)據(jù)內(nèi)容進(jìn)行更新操作幅恋,那么隨后,dataVersion 的值就會變成 1泵肄。即表示的是對數(shù)據(jù)節(jié)點(diǎn)的數(shù)據(jù)內(nèi)容的變更次數(shù)捆交。
版本的作用是用來實(shí)現(xiàn)樂觀鎖機(jī)制中的 “寫入校驗(yàn)” 的。例如腐巢,當(dāng)要修改數(shù)據(jù)節(jié)點(diǎn)的數(shù)據(jù)內(nèi)容時品追,帶上版本號,如果數(shù)據(jù)節(jié)點(diǎn)的版本號與傳入的版本號相等冯丙,就進(jìn)行修改肉瓦,否則修改失敗。
1.6胃惜、Watcher
1.6.1泞莉、概述
Zookeeper 提供了分布式數(shù)據(jù)的發(fā)布/訂閱功能。一個典型的發(fā)布/訂閱模型系統(tǒng)定義了一種一對多的訂閱關(guān)系蛹疯,能夠讓多個訂閱者同時監(jiān)聽某一個主題對象戒财,當(dāng)這個主題對象自身狀態(tài)變化時,會通知所有訂閱者捺弦,使它們能夠做出相應(yīng)的處理饮寞。在 Zookeeper 中,引入了 Watcher 機(jī)制來實(shí)現(xiàn)這種分布式的通知功能列吼。Zookeeper 允許客戶端向服務(wù)端注冊一個 Watcher 監(jiān)聽幽崩,當(dāng)服務(wù)端的一些指定事件觸發(fā)了這個 Watcher,那么就會向指定客戶端發(fā)送一個事件通知來實(shí)現(xiàn)分布式的通知功能寞钥。
從上圖可以看出 Zookeeper 的 Watcher 機(jī)制主要包括客戶端線程慌申、客戶端WatchMananger 和 Zookeeper 服務(wù)器三部分。在具體工作流程上理郑,簡單地講蹄溉,客戶端在向 Zookeeper 服務(wù)器注冊 Watcher 的同時,會將 Watcher 對象存儲在客戶端的 WatchMananger 中您炉。當(dāng) Zookeeper 服務(wù)器端觸發(fā) Watcher 事件后柒爵,會向客戶端發(fā)送通知,客戶端線程從 WatchManager 中取出對應(yīng)的 Watcher 對象來執(zhí)行回調(diào)邏輯赚爵。
1.6.2棉胀、Watcher特性
- 一次性:表示無論是服務(wù)端還是客戶端法瑟,一旦一個 Watcher 被觸發(fā),Zookeeper 都會將其從相應(yīng)的存儲中移除唁奢。因此霎挟,開發(fā)人員在 Watcher 的使用上要記住的一點(diǎn)是需要反復(fù)注冊。
- 客戶端串行執(zhí)行:客戶端 Watcher 回調(diào)的過程是一個串行同步的過程麻掸,這為我們保證了順序酥夭,同時,需要開發(fā)人員注意的一點(diǎn)是脊奋,千萬不要因?yàn)橐粋€ Watcher 的處理邏輯影響了整個客戶端的 Watcher 回調(diào)采郎。
- 輕量:WatchedEvent 是 Zookeeper 整個 Watcher 通知機(jī)制的最小通知單元,這個數(shù)據(jù)結(jié)構(gòu)中只包含三部分內(nèi)容:通知狀態(tài)狂魔、事件類型和節(jié)點(diǎn)路徑。也就是說淫痰,Watcher通知非常簡單最楷,只會告訴客戶端發(fā)生了事件,而不會說明事件的具體內(nèi)容待错。
1.6.3籽孙、watcher接口設(shè)計(jì)
Watcher是一個接口,任何實(shí)現(xiàn)了Watcher接口的類就是一個新的Watcher火俄。Watcher內(nèi)部包含了兩個枚舉類:KeeperState犯建、EventType
-
Watcher通知狀態(tài)(KeeperState)
KeeperState是客戶端與服務(wù)端連接狀態(tài)發(fā)生變化時對應(yīng)的通知類型。路徑為org.apache.zookeeper.Watcher.Event.KeeperState瓜客,是一個枚舉類适瓦,其枚舉屬性如下:
枚舉屬性 | 說明 |
---|---|
SyncConnected | 客戶端與服務(wù)器正常連接時 |
Disconnected | 客戶端與服務(wù)器斷開連接時 |
Expired | 會話session失效時 |
AuthFailed | 身份認(rèn)證失敗時 |
-
Watcher事件類型(EventType)
EventType是數(shù)據(jù)節(jié)點(diǎn)(znode)發(fā)生變化時對應(yīng)的通知類型。EventType變化時KeeperState永遠(yuǎn)處于SyncConnected通知狀態(tài)下谱仪;當(dāng)KeeperState發(fā)生變化時玻熙,EventType永遠(yuǎn)為None。其路徑為org.apache.zookeeper.Watcher.Event.EventType疯攒,是一個枚舉類嗦随,枚舉屬性如下:
枚舉屬性 | 說明 |
---|---|
None | 無 |
NodeCreated | Watcher監(jiān)聽的數(shù)據(jù)節(jié)點(diǎn)被創(chuàng)建時 |
NodeDeleted | Watcher監(jiān)聽的數(shù)據(jù)節(jié)點(diǎn)被刪除時 |
NodeDataChanged | Watcher監(jiān)聽的數(shù)據(jù)節(jié)點(diǎn)內(nèi)容發(fā)生變更時(無論內(nèi)容數(shù)據(jù)是否變化) |
NodeChildrenChanged | Watcher監(jiān)聽的數(shù)據(jù)節(jié)點(diǎn)的子節(jié)點(diǎn)列表發(fā)生變更時 |
注:客戶端接收到的相關(guān)事件通知中只包含狀態(tài)及類型等信息,不包括節(jié)點(diǎn)變化前后的具體內(nèi)容敬尺,變化前的數(shù)據(jù)需業(yè)務(wù)自身存儲枚尼,變化后的數(shù)據(jù)需調(diào)用get等方法重新獲取砂吞;
1.6.4署恍、捕獲相應(yīng)的事件
上面講到zookeeper客戶端連接的狀態(tài)和zookeeper對znode節(jié)點(diǎn)監(jiān)聽的事件類型,下面我們來講解如何建立zookeeper的watcher監(jiān)聽呜舒。在zookeeper中采用zk.getChildren(path, watch)锭汛、zk.exists(path, watch)笨奠、zk.getData(path, watcher, stat)這樣的方式為某個znode注冊監(jiān)聽。
下表以node-x節(jié)點(diǎn)為例唤殴,說明調(diào)用的注冊方法和可監(jiān)聽事件間的關(guān)系:
注冊方式 | Created | ChildrenChanged | Changed | Deleted |
---|---|---|---|---|
zk.exists(“/node-x”,watcher) | 可監(jiān)控 | 可監(jiān)控 | 可監(jiān)控 | |
zk.getData(“/node-x”,watcher) | 可監(jiān)控 | 可監(jiān)控 | ||
zk.getChildren(“/node-x”,watcher) | 可監(jiān)控 | 可監(jiān)控 |
1.7般婆、ACL
Zookeeper 中提供了一套完善的 ACL(Access Control List)權(quán)限控制機(jī)制來保障數(shù)據(jù)的安全。
1.7.1朵逝、概述
ACL 由三部分組成蔚袍,分別是:權(quán)限模式(Scheme)、授權(quán)對象(ID)和權(quán)限(Permission)配名,通常使用“scheme: ?id:permission”來標(biāo)識一個有效的ACL 信息啤咽。下面分別介紹:
-
權(quán)限模式(Scheme)
方案 說明 world 只有一個用戶:anyone,代表登錄 Zookeeper 所有人(默認(rèn)) ip 對客戶端使用IP地址認(rèn)證渠脉。 auth 使用已添加認(rèn)證的用戶認(rèn)證宇整。 digest 使用“用戶名:密碼”方式認(rèn)證。
-
授權(quán)對象(ID)
授權(quán)對象ID是指芋膘,權(quán)限賦予的實(shí)體鳞青,例如:IP 地址或用戶。
-
權(quán)限(Permission)
權(quán)限 ACL簡寫 描述 create c 可以創(chuàng)建子節(jié)點(diǎn)为朋。 delete d 可以刪除子節(jié)點(diǎn)(僅下一級節(jié)點(diǎn))臂拓。 read r 可以讀取節(jié)點(diǎn)數(shù)據(jù)或子節(jié)點(diǎn)列表。 write w 可以對節(jié)點(diǎn)進(jìn)行更新操作习寸。 admin a 可以設(shè)置節(jié)點(diǎn)訪問控制列表權(quán)限胶惰。
1.7.2、特性
- zooKeeper的權(quán)限控制是基于每個znode節(jié)點(diǎn)的霞溪,需要對每個節(jié)點(diǎn)設(shè)置權(quán)限孵滞。
- 每個znode支持設(shè)置多種權(quán)限控制方案和多個權(quán)限。
- 子節(jié)點(diǎn)不會繼承父節(jié)點(diǎn)的權(quán)限鸯匹,客戶端無權(quán)訪問某節(jié)點(diǎn)剃斧,但可能可以訪問它的子節(jié)點(diǎn)。
1.7.3忽你、案例
-
world授權(quán)模式
命令
setAcl <path> world:anyone:<acl>
案例
[zk: localhost:2181(CONNECTED) 0] create /node1 "node1" Created /node1 [zk: localhost:2181(CONNECTED) 1] getAcl /node1 'world,'anyone : cdrwa [zk: localhost:2181(CONNECTED) 2] setAcl /node1 world:anyone:crwa cZxid = 0x100000004 ctime = Fri May 29 14:31:54 CST 2020 mZxid = 0x100000004 mtime = Fri May 29 14:31:54 CST 2020 pZxid = 0x100000004 cversion = 0 dataVersion = 0 aclVersion = 1 ephemeralOwner = 0x0 dataLength = 5 numChildren = 0
-
IP授權(quán)模式
命令
setAcl <path> ip:<ip>:<acl>
案例
注意:遠(yuǎn)程登錄zookeeper命令:./zkCli.sh -server ip
[zk: localhost:2181(CONNECTED) 18] create /node2 "node2" Created /node2 [zk: localhost:2181(CONNECTED) 23] setAcl /node2 ip:192.168.150.101:cdrwa cZxid = 0xe ctime = Fri Dec 13 22:30:29 CST 2019 mZxid = 0x10 mtime = Fri Dec 13 22:33:36 CST 2019 pZxid = 0xe cversion = 0 dataVersion = 2 aclVersion = 1 ephemeralOwner = 0x0 dataLength = 20 numChildren = 0 [zk: localhost:2181(CONNECTED) 25] getAcl /node2 'ip,'192.168.150.101 : cdrwa #使用IP非 192.168.150.101 的機(jī)器 [zk: localhost:2181(CONNECTED) 0] get /node2 Authentication is not valid : /node2 #沒有權(quán)限
-
Auth授權(quán)模式
命令
addauth digest <user>:<password> #添加認(rèn)證用戶 setAcl <path> auth:<user>:<acl>
案例
[zk: localhost:2181(CONNECTED) 6] create /node3 "node3" Created /node3 #添加認(rèn)證用戶 [zk: localhost:2181(CONNECTED) 7] addauth digest ld:123456 [zk: localhost:2181(CONNECTED) 8] setAcl /node3 auth:ld:cdrwa cZxid = 0x10000000c ctime = Fri May 29 14:47:13 CST 2020 mZxid = 0x10000000c mtime = Fri May 29 14:47:13 CST 2020 pZxid = 0x10000000c cversion = 0 dataVersion = 0 aclVersion = 1 ephemeralOwner = 0x0 dataLength = 5 numChildren = 0 [zk: localhost:2181(CONNECTED) 9] getAcl /node3 'digest,'ld:kesl2p6Yx58a+/mP+TKSFZkzkZ0= : cdrwa #添加認(rèn)證用戶后可以訪問 [zk: localhost:2181(CONNECTED) 10] get /node3 node3 cZxid = 0x10000000c ctime = Fri May 29 14:47:13 CST 2020 mZxid = 0x10000000c mtime = Fri May 29 14:47:13 CST 2020 pZxid = 0x10000000c cversion = 0 dataVersion = 0 aclVersion = 1 ephemeralOwner = 0x0 dataLength = 5 numChildren = 0
-
Digest授權(quán)模式
命令
setAcl <path> digest:<user>:<password>:<acl>
這里的密碼是經(jīng)過SHA1及BASE64處理的密文幼东,在SHELL中可以通過以下命令計(jì)算:
echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
先來計(jì)算一個密文
echo -n monkey:123456 | openssl dgst -binary -sha1 | openssl base64
案例
[zk: localhost:2181(CONNECTED) 12] create /node4 "node4" Created /node4 [zk: localhost:2181(CONNECTED) 13] setAcl /node4 digest:monkey:Rk6u/zJJdOYrTZ6+J0p4/4gTILg=:cdrwa cZxid = 0x10000000e ctime = Fri May 29 14:52:50 CST 2020 mZxid = 0x10000000e mtime = Fri May 29 14:52:50 CST 2020 pZxid = 0x10000000e cversion = 0 dataVersion = 0 aclVersion = 1 ephemeralOwner = 0x0 dataLength = 5 numChildren = 0 #沒有權(quán)限無法讀取 [zk: localhost:2181(CONNECTED) 14] getAcl /node4 Authentication is not valid : /node4 #添加認(rèn)證用戶 [zk: localhost:2181(CONNECTED) 15] addauth digest monkey:123456 [zk: localhost:2181(CONNECTED) 16] getAcl /node4 'digest,'monkey:Rk6u/zJJdOYrTZ6+J0p4/4gTILg= : cdrwa [zk: localhost:2181(CONNECTED) 17] get /node4 node4 cZxid = 0x10000000e ctime = Fri May 29 14:52:50 CST 2020 mZxid = 0x10000000e mtime = Fri May 29 14:52:50 CST 2020 pZxid = 0x10000000e cversion = 0 dataVersion = 0 aclVersion = 1 ephemeralOwner = 0x0 dataLength = 5 numChildren = 0
-
多種模式授權(quán)
同一個節(jié)點(diǎn)可以同時使用多種模式授權(quán)
[zk: localhost:2181(CONNECTED) 18] create /node5 "node5" Created /node5 [zk: localhost:2181(CONNECTED) 19] addauth digest ld:123456 [zk: localhost:2181(CONNECTED) 20] setAcl /node5 ip:192.168.150.101:cdrwa,auth:ld:cdrwa cZxid = 0x100000010 ctime = Fri May 29 14:56:38 CST 2020 mZxid = 0x100000010 mtime = Fri May 29 14:56:38 CST 2020 pZxid = 0x100000010 cversion = 0 dataVersion = 0 aclVersion = 1 ephemeralOwner = 0x0 dataLength = 5 numChildren = 0
1.7.4、ACL 超級管理員
zookeeper的權(quán)限管理模式有一種叫做super科雳,該模式提供一個超管可以方便的訪問任何權(quán)限的節(jié)點(diǎn)
假設(shè)這個超管是:super:admin根蟹,需要先為超管生成密碼的密文
echo -n super:admin | openssl dgst -binary -sha1 | openssl base64
那么打開zookeeper目錄下的/bin/zkServer.sh服務(wù)器腳本文件,找到如下一行:
nohup $JAVA "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}"
這就是腳本中啟動zookeeper的命令糟秘,默認(rèn)只有以上兩個配置項(xiàng)简逮,我們需要加一個超管的配置項(xiàng)
"-Dzookeeper.DigestAuthenticationProvider.superDigest=super:xQJmxLMiHGwaqBvst5y6rkB6HQs="
那么修改以后這條完整命令變成了
nohup $JAVA "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" "-Dzookeeper.DigestAuthenticationProvider.superDigest=super:xQJmxLMiHGwaqBvst5y6rkB6HQs="\
-cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 < /dev/null &
之后啟動zookeeper,輸入如下命令添加權(quán)限
addauth digest super:admin #添加認(rèn)證用戶
2、Leader 選舉
2.1尿赚、服務(wù)器狀態(tài)
- looking:尋找leader狀態(tài)散庶。當(dāng)服務(wù)器處于該狀態(tài)時蕉堰,它會認(rèn)為當(dāng)前集群中沒有Leader,因此需要進(jìn)入 Leader 選舉流程悲龟。
- leading:領(lǐng)導(dǎo)者狀態(tài)屋讶。表明當(dāng)前服務(wù)器角色是leader。
- following:跟隨者狀態(tài)须教。表明當(dāng)前服務(wù)器角色是follower皿渗。
- observing:觀察者狀態(tài)。表明當(dāng)前服務(wù)器角色是observer轻腺。
2.2乐疆、服務(wù)器啟動時期的 Leader 選舉
在服務(wù)器集群初始化階段,我們以 3 臺機(jī)器組成的服務(wù)器集群為例贬养,當(dāng)有一臺服務(wù)器server1 啟動的時候挤土,它是無法進(jìn)行 Leader 選舉的,當(dāng)?shù)诙_機(jī)器 server2 也啟動時误算,此時這兩臺服務(wù)器已經(jīng)能夠進(jìn)行互相通信耕挨,每臺機(jī)器都試圖找到一個 Leader,于是便進(jìn)入了 Leader 選舉流程尉桩。
每個server發(fā)出一個投票。由于是初始情況贪庙,server1和server2都會將自己作為leader服務(wù)器來進(jìn)行投票蜘犁,每次投票會包含所推舉的服務(wù)器的myid和zxid,使用(myid, zxid)來表示止邮,此時server1的投票為(1, 0)这橙,server2的投票為(2, 0),然后各自將這個投票發(fā)給集群中其他機(jī)器导披。
集群中的每臺服務(wù)器接收來自集群中各個服務(wù)器的投票屈扎。
-
處理投票。針對每一個投票撩匕,服務(wù)器都需要將別人的投票和自己的投票進(jìn)行pk鹰晨,pk規(guī)則如下
- 優(yōu)先檢查zxid。zxid比較大的服務(wù)器優(yōu)先作為leader止毕。
- 如果zxid相同模蜡,那么就比較myid。myid較大的服務(wù)器作為leader服務(wù)器扁凛。
? 對于Server1而言忍疾,它的投票是(1, 0),接收Server2的投票為(2, 0)谨朝,首先會比較兩者的zxid卤妒,均為0甥绿,再比較myid,此時server2的myid最大则披,于是更新自己的投票為(2, 0)共缕,然后重新投票,對于server2而言收叶,其無須更新自己的投票骄呼,只是再次向集群中所有機(jī)器發(fā)出上一次投票信息即可。
統(tǒng)計(jì)投票判没。每次投票后蜓萄,服務(wù)器都會統(tǒng)計(jì)投票信息,判斷是否已經(jīng)有過半機(jī)器接受到相同的投票信息澄峰,對于server1嫉沽、server2而言,都統(tǒng)計(jì)出集群中已經(jīng)有兩臺機(jī)器接受了(2, 0)的投票信息俏竞,此時便認(rèn)為已經(jīng)選出了leader绸硕。
改變服務(wù)器狀態(tài)。一旦確定了leader魂毁,每個服務(wù)器就會更新自己的狀態(tài)玻佩,如果是follower,那么就變更為following席楚,如果是leader咬崔,就變更為leading。
2.3烦秩、服務(wù)器運(yùn)行時期的 Leader 選舉
在zookeeper運(yùn)行期間垮斯,leader與非leader服務(wù)器各司其職,即便當(dāng)有非leader服務(wù)器宕機(jī)或新加入只祠,此時也不會影響leader兜蠕,但是一旦leader服務(wù)器掛了,那么整個集群將暫停對外服務(wù)抛寝,進(jìn)入新一輪leader選舉熊杨,其過程和啟動時期的Leader選舉過程基本一致。
假設(shè)正在運(yùn)行的有server1盗舰、server2猴凹、server3三臺服務(wù)器,當(dāng)前l(fā)eader是server2岭皂,若某一時刻leader掛了郊霎,此時便開始Leader選舉。選舉過程如下:
- 變更狀態(tài)爷绘。leader掛后书劝,余下的非 Observer 服務(wù)器都會將自己的服務(wù)器狀態(tài)變更為looking进倍,然后開始進(jìn)入leader選舉過程。
- 每個server會發(fā)出一個投票购对。在運(yùn)行期間猾昆,每個服務(wù)器上的zxid可能不同,此時假定server1的zxid為123骡苞,server3的zxid為122垂蜗,在第一輪投票中,server1和server3都會投自己解幽,產(chǎn)生投票(1, 123)贴见,(3, 122),然后各自將投票發(fā)送給集群中所有機(jī)器躲株。
- 接收來自各個服務(wù)器的投票片部。
- 處理投票。對于投票的處理霜定,和上面提到的服務(wù)器啟動期間的處理規(guī)則是一致的档悠。在這個例子里面,由于 Server1 的 zxid 為 123望浩,Server3 的 zxid 為 122辖所,那么顯然,Server1 會成為 Leader磨德。
- 統(tǒng)計(jì)投票缘回。
- 改變服務(wù)器狀態(tài)。
2.4剖张、Observer 角色及其設(shè)置
observer角色特點(diǎn):
- 不參與集群的leader選舉
- 不參與集群中寫數(shù)據(jù)時的ack反饋
為了使用observer角色,在任何想變成observer角色的配置文件中加入如下配置:
peerType=observer
并在所有server的配置文件中揩环,配置成observer模式的server的那行配置追加:observer搔弄,例如:
server.3=192.168.60.130:2289:3389:observer