概述
Zookeeper字面上理解就是動物管理員,是大數(shù)據(jù)框架Hadoop生態(tài)圈中的一個服務(wù)中間件熊赖,Hadoop生態(tài)圈中很多開源項(xiàng)目使用動物命名来屠,那么需要一個管理員來管理這些“動物”。他負(fù)責(zé)分布式應(yīng)用程序協(xié)調(diào)的工作震鹉。
Zookeeper主要提供以下四點(diǎn)功能:統(tǒng)一命名服務(wù)俱笛、配置管理、集群管理传趾、共享鎖和隊(duì)列管理
迎膜,用于高效的管理集群的運(yùn)行。
Zookeeper通過心跳機(jī)制可以檢測掛掉的機(jī)器并將掛掉機(jī)器的ip和服務(wù)對應(yīng)關(guān)系從列表中刪除浆兰。
Zookeeper 部署有三種方式磕仅,單機(jī)模式、集群模式簸呈、偽集群模式榕订,以下采用Docker 的方式部署
注意: 集群為大于等于3個奇數(shù),如 3蜕便、5劫恒、7,不宜太多,集群機(jī)器多了選舉和數(shù)據(jù)同步耗時長玩裙,不穩(wěn)定兼贸。
zk安裝
docker-compose-yml
version: '3.1'
services:
zoo1:
image: zookeeper
restart: always
hostname: zoo1
ports:
- 2181:2181
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=zoo1:2888:3888
配置說明
- 2181:客戶端連接 Zookeeper 集群使用的監(jiān)聽端口號
- 3888:選舉 leader 使用
- 2888:集群內(nèi)機(jī)器通訊使用(Leader 和 Follower 之間數(shù)據(jù)同步使用的端口號,Leader 監(jiān)聽此端口)
驗(yàn)證是否安裝成功
- 以交互的方式進(jìn)入容器
docker exec -it zookeeper_zoo1_1 /bin/bash
- 使用客戶端連接到服務(wù)端
bash-4.3# ./bin/zkCli.sh
Connecting to localhost:2181
- 使用服務(wù)端工具檢查服務(wù)器狀態(tài)
bash-4.3# ./bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /conf/zoo.cfg
Mode: standalone
ZK集群安裝
略
可以參考這個網(wǎng)頁
https://www.cnblogs.com/kingkoo/p/8732448.html
ZK常用命令
命令 | 作用 | 示例 |
---|---|---|
help | 查看zk命令清單 | help |
ls | 列出文件及目錄 | ls / |
create | 創(chuàng)建節(jié)點(diǎn) | create /test "bb"吃溅、create -e /test/e1 "bb" |
get | 獲取節(jié)點(diǎn)信息 | get /test/e1 |
set | 修改節(jié)點(diǎn)內(nèi)容 | set /aa haha123 |
delete | 刪除節(jié)點(diǎn) | delete /test |
通過上面的命令操作溶诞,我們不難看出ZK是通過一個特殊的文件系統(tǒng),幫我們系統(tǒng)分布式系統(tǒng)間的協(xié)調(diào)决侈。
- 原則性:根據(jù)文件系統(tǒng)的原子性螺垢,同一個目錄下不能創(chuàng)建2個相同的文件
- 獨(dú)特性:可以創(chuàng)建跟客戶端綁定的臨時文件
服務(wù)器命令
./zkServer.sh start //啟動服務(wù)
./zkServer.sh stop //停止服務(wù)
./zkServer.sh restart //重啟服務(wù)器
./zkServer.sh //執(zhí)行狀態(tài)
注:Zookeeper不能用于存放大量的數(shù)據(jù),每個節(jié)點(diǎn)的存放數(shù)據(jù)上限為1M
什么是分布式鎖
為了防止分布式系統(tǒng)中的多個進(jìn)程之間相互干擾赖歌,我們需要一種分布式協(xié)調(diào)技術(shù)來對這些進(jìn)程進(jìn)行調(diào)度枉圃。而這個分布式協(xié)調(diào)技術(shù)的核心就是來實(shí)現(xiàn)這個分布式鎖。
比如:12306搶票庐冯,10W人搶同一張火車票孽亲。這個時候用戶并發(fā)數(shù)已經(jīng)超過了mysql所能承受的極限,無法再用數(shù)據(jù)庫實(shí)現(xiàn)分布式鎖展父,必須通過zk等來實(shí)現(xiàn)返劲。
分布式鎖的實(shí)現(xiàn)有哪些
- Memcached:利用 Memcached 的
add
命令。此命令是原子性操作栖茉,只有在key
不存在的情況下篮绿,才能add
成功,也就意味著線程得到了鎖吕漂。 - Redis:和 Memcached 的方式類似亲配,利用 Redis 的
setnx
命令。此命令同樣是原子性操作惶凝,只有在key
不存在的情況下吼虎,才能set
成功。 - Zookeeper:利用 Zookeeper 的順序臨時節(jié)點(diǎn)苍鲜,來實(shí)現(xiàn)分布式鎖和等待隊(duì)列鲸睛。Zookeeper 設(shè)計的初衷,就是為了實(shí)現(xiàn)分布式鎖服務(wù)的坡贺。
- Chubby:Google 公司實(shí)現(xiàn)的粗粒度分布式鎖服務(wù)官辈,底層利用了 Paxos 一致性算法。
Zookeeper 的數(shù)據(jù)模型
Zookeeper 的數(shù)據(jù)模型是什么樣子呢遍坟?它很像數(shù)據(jù)結(jié)構(gòu)當(dāng)中的樹拳亿,也很像文件系統(tǒng)的目錄。
樹是由節(jié)點(diǎn)所組成愿伴,Zookeeper 的數(shù)據(jù)存儲也同樣是基于節(jié)點(diǎn)肺魁,這種節(jié)點(diǎn)叫做 Znode
但是,不同于樹的節(jié)點(diǎn)隔节,Znode 的引用方式是路徑引用鹅经,類似于文件路徑:
/動物/貓
/汽車/寶馬
這樣的層級結(jié)構(gòu)寂呛,讓每一個 Znode 節(jié)點(diǎn)擁有唯一的路徑,就像命名空間一樣對不同信息作出清晰的隔離瘾晃。
Znode 包含哪些元素
- data:Znode 存儲的數(shù)據(jù)信息贷痪。
- ACL:記錄 Znode 的訪問權(quán)限,即哪些人或哪些 IP 可以訪問本節(jié)點(diǎn)蹦误。
- stat:包含 Znode 的各種元數(shù)據(jù)劫拢,比如事務(wù) ID、版本號强胰、時間戳舱沧、大小等等。
- child:當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)引用
這里需要注意一點(diǎn)偶洋,Zookeeper 是為讀多寫少的場景所設(shè)計熟吏。Znode 并不是用來存儲大規(guī)模業(yè)務(wù)數(shù)據(jù),而是用于存儲少量的狀態(tài)和配置信息玄窝,每個節(jié)點(diǎn)的數(shù)據(jù)最大不能超過 1MB
分俯。
Zookeeper 的事件通知
Zookeeper 客戶端在請求讀操作的時候,可以選擇是否設(shè)置 Watch哆料。我們可以把 Watch 理解成是注冊在特定 Znode 上的觸發(fā)器缸剪。當(dāng)這個 Znode 發(fā)生改變,也就是調(diào)用了 create
东亦,delete
杏节,setData
方法的時候,將會觸發(fā) Znode 上注冊的對應(yīng)事件典阵,請求 Watch 的客戶端會接收到異步通知奋渔。
具體交互過程如下:
- 客戶端調(diào)用
getData
方法,watch
參數(shù)是true
壮啊。服務(wù)端接到請求嫉鲸,返回節(jié)點(diǎn)數(shù)據(jù),并且在對應(yīng)的哈希表里插入被 Watch 的 Znode 路徑歹啼,以及 Watcher 列表玄渗。
- 當(dāng)被 Watch 的 Znode 已刪除,服務(wù)端會查找哈希表狸眼,找到該 Znode 對應(yīng)的所有 Watcher藤树,異步通知客戶端,并且刪除哈希表中對應(yīng)的 Key-Value拓萌。
Zookeeper 的一致性
Zookeeper 身為分布式系統(tǒng)協(xié)調(diào)服務(wù)岁钓,如果自身掛了如何處理呢?為了防止單機(jī)掛掉的情況,Zookeeper 維護(hù)了一個集群屡限。如下圖:
Zookeeper Service 集群是一主多從結(jié)構(gòu)品嚣。
在更新數(shù)據(jù)時,首先更新到主節(jié)點(diǎn)(這里的節(jié)點(diǎn)是指服務(wù)器钧大,不是 Znode)翰撑,再同步到從節(jié)點(diǎn)。
在讀取數(shù)據(jù)時拓型,直接讀取任意從節(jié)點(diǎn)额嘿。
為了保證主從節(jié)點(diǎn)的數(shù)據(jù)一致性瘸恼,Zookeeper 采用了 ZAB 協(xié)議劣挫,這種協(xié)議非常類似于一致性算法 Paxos和 Raft。
什么是 ZAB
Zookeeper Atomic Broadcast东帅,有效解決了 Zookeeper 集群崩潰恢復(fù)压固,以及主從同步數(shù)據(jù)的問題。
ZAB 協(xié)議定義的三種節(jié)點(diǎn)狀態(tài)
- Looking :選舉狀態(tài)靠闭。
- Following :Follower 節(jié)點(diǎn)(從節(jié)點(diǎn))所處的狀態(tài)帐我。
- Leading :Leader 節(jié)點(diǎn)(主節(jié)點(diǎn))所處狀態(tài)。
最大 ZXID
最大 ZXID 也就是節(jié)點(diǎn)本地的最新事務(wù)編號愧膀,包含 epoch 和計數(shù)兩部分拦键。epoch 是紀(jì)元的意思,相當(dāng)于 Raft 算法選主時候的 term檩淋。
ZAB 的崩潰恢復(fù)
假如 Zookeeper 當(dāng)前的主節(jié)點(diǎn)掛掉了芬为,集群會進(jìn)行崩潰恢復(fù)。ZAB 的崩潰恢復(fù)分成三個階段:
Leader election
選舉階段蟀悦,此時集群中的節(jié)點(diǎn)處于 Looking 狀態(tài)媚朦。它們會各自向其他節(jié)點(diǎn)發(fā)起投票,投票當(dāng)中包含自己的服務(wù)器 ID 和最新事務(wù) ID(ZXID)日戈。
接下來询张,節(jié)點(diǎn)會用自身的 ZXID 和從其他節(jié)點(diǎn)接收到的 ZXID 做比較,如果發(fā)現(xiàn)別人家的 ZXID 比自己大浙炼,也就是數(shù)據(jù)比自己新份氧,那么就重新發(fā)起投票,投票給目前已知最大的 ZXID 所屬節(jié)點(diǎn)弯屈。
每次投票后半火,服務(wù)器都會統(tǒng)計投票數(shù)量,判斷是否有某個節(jié)點(diǎn)得到半數(shù)以上的投票季俩。如果存在這樣的節(jié)點(diǎn)钮糖,該節(jié)點(diǎn)將會成為準(zhǔn) Leader,狀態(tài)變?yōu)?Leading。其他節(jié)點(diǎn)的狀態(tài)變?yōu)?Following店归。
Discovery
發(fā)現(xiàn)階段阎抒,用于在從節(jié)點(diǎn)中發(fā)現(xiàn)最新的 ZXID 和事務(wù)日志∠矗或許有人會問:既然 Leader 被選為主節(jié)點(diǎn)且叁,已經(jīng)是集群里數(shù)據(jù)最新的了,為什么還要從節(jié)點(diǎn)中尋找最新事務(wù)呢秩伞?
這是為了防止某些意外情況逞带,比如因網(wǎng)絡(luò)原因在上一階段產(chǎn)生多個 Leader 的情況。
所以這一階段纱新,Leader 集思廣益展氓,接收所有 Follower 發(fā)來各自的最新 epoch 值谴分。Leader 從中選出最大的 epoch币他,基于此值加 1辩昆,生成新的 epoch 分發(fā)給各個 Follower粟焊。
各個 Follower 收到全新的 epoch 后舀奶,返回 ACK 給 Leader管跺,帶上各自最大的 ZXID 和歷史事務(wù)日志锭亏。Leader 選出最大的 ZXID咖城,并更新自身歷史日志族檬。
Synchronization
同步階段歪赢,把 Leader 剛才收集得到的最新歷史事務(wù)日志,同步給集群中所有的 Follower单料。只有當(dāng)半數(shù) Follower 同步成功埋凯,這個準(zhǔn) Leader 才能成為正式的 Leader。
自此看尼,故障恢復(fù)正式完成递鹉。
選舉原理總結(jié)
- 每個 server 發(fā)出一個投票: 投票的最基本元素是(SID-服務(wù)器id,ZXID-事物id)
- 接受來自各個服務(wù)器的投票
處理投票:優(yōu)先檢查 ZXID(數(shù)據(jù)越新ZXID越大),ZXID比較大的作為leader,ZXID一樣的情況下比較SID
- 接受來自各個服務(wù)器的投票
- 統(tǒng)計投票:這里有個過半的概念藏斩,大于集群機(jī)器數(shù)量的一半躏结,即大于或等于(n/2+1),我們這里的由三臺,大于等于2即為達(dá)到“過半”的要求狰域。這里也有引申到為什么 Zookeeper 集群推薦是單數(shù)媳拴。
Zookeeper同步流程
選完Leader以后,zk就進(jìn)入狀態(tài)同步過程兆览。
1屈溉、Leader等待server連接;
2抬探、Follower連接leader子巾,將最大的zxid發(fā)送給leader帆赢;
3、Leader根據(jù)follower的zxid確定同步點(diǎn)线梗;
4椰于、完成同步后通知follower 已經(jīng)成為uptodate狀態(tài);
5仪搔、Follower收到uptodate消息后瘾婿,又可以重新接受client的請求進(jìn)行服務(wù)了。
Java三種ZooKeeper客戶端比較
原生 | zkClient | Curator |
---|---|---|
直接使用Zookeeper原生API的人并不多烤咧,因?yàn)? 1)連接的創(chuàng)建是異步的偏陪,需要開發(fā)人員自行編碼實(shí)現(xiàn)等待 2)連接沒有超時自動的重連機(jī)制 3)Zookeeper本身沒提供序列化機(jī)制,需要開發(fā)人員自行指定煮嫌,從而實(shí)現(xiàn)數(shù)據(jù)的序列化和反序列化 4)Watcher注冊一次只會生效一次,需要不斷的重復(fù)注冊 5)Watcher的使用方式不符合java本身的術(shù)語笛谦,如果采用監(jiān)聽器方式,更容易理解 6)不支持遞歸創(chuàng)建樹形節(jié)點(diǎn) |
ZkClient是Github上的一個開源Zookeeper客戶端立膛,是由Datameer工程師Stefan Groschupf和Peter Voss一起開發(fā)揪罕。ZkClient在原生Zookeeper api的基礎(chǔ)上進(jìn)行封裝梯码,是一個更易用的客戶端宝泵,解決和如下問題: 1)session會話超時重連 2)解決Watcher反復(fù)注冊 3)簡化API開發(fā) |
Curator是Netflix公司開源的一套Zookeeper客戶端框架,作者是Jordan Zimmerman轩娶。Curator解決除了ZkClient提供的功能外儿奶,新增如下功能: 1)提供了一套Fluent風(fēng)格的客戶端API框架。 2)提供了各種應(yīng)用場景(Recipe,如共享鎖服務(wù)鳄抒、Master選舉機(jī)制和分布式計數(shù)器)的抽樣封裝闯捎。 |