Zookeeper框架基礎筆記

視頻教程傳送門 -> https://www.bilibili.com/video/BV19b411772h

1. Zookeeper

Zookeeper是一個分佈式協調服務的開源框架。
Zookeeper本質是一個分佈式的小文件存儲系統。

@Zookeeper特性
1)全局數據一致:每個服務器保存一份相同的數據副本,客戶端無論連接哪個服務器展示的數據是一致的
2)可靠性:消息(即增刪改查)被一臺服務器接受,那麼也將被所有服務器接受
3)順序性:全局有序 -- 在一臺服務器上,如果消息a在消息b前發佈,則在所有服務器上都是如此
                    偏序 -- 消息b在消息a後被同一個發送着發佈,a必將排在b前面
4)數據更新原子性:一次數據更新要麼成功(半數以上節點成功),要麼失敗
5)實時性:Zookeeper保證客戶端將在一個時間間隔範圍內獲得服務器的更新信息,或者服務器失效的信息

ZooKeeper具備CP特性
任何時刻的訪問請求能得到一致的數據結果
系統對網絡分割具備容錯性
不保證每次服務請求的可用性

@Zookeeper集羣角色

Leader
Zookeeper集羣工作的核心
事務請求(寫操作)的唯一調度和處理者,保證集羣事務處理的順序性
集羣內部各個服務器的調度者

說明:對於create、setData、delete等有寫操作的請求,需要統一轉發給Leader處理,Leader需要決定編號、執行操作,這個過程成爲一個事務。

Follower
處理客戶端非事務(讀操作)請求,轉發事務請求給Leader
參與集羣Leader選舉投票

Observer   針對訪問量比較大的Zookeeper集羣,可以增加觀察者角色(橫向擴展)
提供非事務服務、不參加投票

@Zookeeper集羣搭建
Zookeeper集羣通常由2n+1臺服務器組成(Leader選舉基於Paxos算法實現)
1)Leader+Follower模式
- 配置主機名稱和IP地址映射
- 修改Zookeeper配置文件
- 遠程複製分發安裝文件
- 設置myid
- 啓動Zookeeper集羣

2)啓用Observer模式
可在對應節點的配置文件添加 peerType=observer
並且在配置文件指定哪些節點被指定爲Observer,如
server.1:localhost:2181:3181:observer

以3臺服務器爲例,搭建步驟如下

step1 
確認環境已安裝jdk
檢查集羣時間是否同步
檢查防火牆是否關閉(生產環境配置防火牆規則)
檢查是否配置主機IP映射

step2
tar -xzvf zookeeper-xxx.tar.gz
mv zookeeper-xxx zookeeper

step3
修改環境變量(3臺Zookeeper都要修改)
vi /etc/profile 添加如下行
export ZOOKEEPER_HOME=/home/hadoop/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin
source /etc/profile

step4
修改Zookeeper配置文件(先在一臺修改)
cd zookeeper/conf
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg 添加如下行
#可以修改數據路徑
dataDir=/root/apps/zookeeper/zkdata
#兩個端口分別是 心跳端口、選舉端口
server.1=node-1:2888:3888
server.2=node-2:2888:3888
server.3=node-3:2888:3888

創建文件myid
cd /root/apps/zookeeper/zkdata
echo 1 > myid

step5 
分發安裝包到其它服務器
scp -r /root/apps root@node-1:/
scp -r /root/apps root@node-2:/

step6
修改其它服務器的myid文件
服務器node-1 修改myid內容爲2
服務器node-2 修改myid內容爲3

step7
在每臺服務器啓動zookeeper
cd bin
./zkServer.sh start

查看狀態(還可以看到是leader還是follower)
./zkServer.sh status

 

2. Zookeeper數據模型

@Znode特點
類似於文件系統的目錄樹,但也有的不同之處,其特點如下
1)Znode兼具文件和目錄兩種特點
   - 既像文件一樣維護數據、元信息、ACL、時間戳等數據結構
   - 又像目錄一樣可以作爲路徑標識的一部分,且可以具有子Znode
   用戶可以對Znode具有增刪改查

2)Znode具有原子性操作
   - 讀操作將獲取與節點相關的所有數據
   - 寫操作將替換掉節點的所有數據
每一個節點都擁有自己的ACL(訪問控制列表),這個列表限定了特定用戶對目標節點可以執行的操作

3)Znode存儲數據大小有限制
Zookeeper雖然可以關聯一些數據,但並沒有被設計爲常規的數據庫或者大數據存儲
相反,它用來管理調度數據,如分佈式應用中的配置文件信息、狀態信息、彙集位置等(都是很小的數據,KB級)
Zookeeper的服務器和客戶端都被設計爲嚴格檢查並限制每個Znode的數據大小至多1M

4)Znode通過路徑引用 
路徑必須是絕對路徑、且是唯一的

@Znode組成
每個Znode由3部分組成
stat 狀態信息,描述Znode版本、權限等信息
data 與該Znode關聯的數據
children 該Znode下的子節點

@Znode節點類型
臨時節點&永久節點
臨時節點:該節點的生命週期依賴於創建它們的會話
                  會話結束臨時節點將被自動刪除,也可以手動刪除
                  臨時節點不允許擁有子節點
永久節點:該節點的生命週期不依賴於會話,執行刪除操作纔會被刪除

Znode的序列特性
如果創建的時候指定的話,該Znode的名字後面會自動追加一個不斷增加的序列號
序列號記錄每個子節點創建的先後順序,對於此節點的父節點來說是唯一的
序列號的格式爲"%10d"(10位數字,沒有數值的數位用0補充)

@Znode屬性
通過命令get,可以獲得節點的屬性

dataVersion:數據版本號,每次對節點進行set操作,dataVersion的值都會增加1(即使設置的是相同數據)
                      可以有效避免數據更新時出現的先後順序問題
cversion:子節點的版本號,當Znode的子節點發生變化時,cversion的值就會加1
aclVersion:ACL的版本號
cZxid:Znode創建的事務id
mZxid:Znode被修改的事務id,每次對Znode的修改都會更新該值
             對於zk來說,每次的變化都會產生一個唯一的事務id,zxid(Zookeeper Transaction  Id)
             通過zxid可以確定更新操作的先後順序。例如,如果zxid1小於zxid2,說明zxid1操作先於zxid2發生
             zxid對於整個zk都是唯一的,即使操作的是不同的znode
ctime:節點創建時的時間戳
mtime:節點最新一次更新發生時的時間戳
ephemeralOwner:如果該節點位臨時節點,ephemeralOwner值表示與該節點綁定的session id;反之,ephemeralOwner爲0
在client和server通信之前,首先需要建立連接(session),連接建立後,如果發生連接超時、授權失敗、顯式關閉連接,連接處於CLOSED狀態,此時session結束

3. Zookeeper shell

@客戶端連接
運行 zkCli.sh -server ip 進入命令行工具
輸入help,輸出zk shell提示
說明:-server可選,不帶會在本機查找zk,帶上連接到遠端zk

@shell基本操作
1)創建節點
create [-s] [-e] path data acl
-s指定創建順序節點
-e指定創建臨時節點
acl用來進行權限控制

2)讀取節點
ls 命令   列出Zookeeper指定節點下的所有子節點(只能查看第一級子節點)
get 命令  獲取指定Znode的數據內容和屬性信息
ls2 命令   列出的信息比ls詳細,包括子節點和屬性信息,但不包括數據內容

ls path [watch]
get path [watch]
ls2 path [watch]

3)更新節點
set path data [version]
data 更新的新內容
version 數據的版本
更新後dataVersion會遞增

4)刪除節點
delete path [version]
若刪除的節點存在子節點則無法刪除
可以先刪除子節點
或者使用 rmr path 遞歸刪除節點

5)quata
setquota -n|-b val path 對節點增加限制
-n 表示子節點的最大個數
-b 表示數據值的最大長度
val 子節點的最大個數或數據值的最大長度
path 節點路徑

listquota path 列出指定節點的quota

delquota [-n|-b] path 刪除quota

注意:即使節點數超了,仍能創建,會在日誌zookeeper.out中打印WARN

6)history列出命令歷史
redo重新執行指定命令編號的歷史命令

4. Zookeeper Watcher

Zookeeper提供了分佈式數據發佈/訂閱功能
一對多訂閱=> 能讓多個訂閱者同時監聽某一個主題對象
當主題對象自身狀態變化時,會通知所有訂閱者

Zookeeper引入Watcher機制來實現分佈式通知功能
Zookeeper允許客戶端向服務器註冊一個Watcher監聽,當服務端的一些事件觸發了這個Watcher,就會向指定的客戶端發送一個事件來通知
觸發事件的種類有節點創建、節點刪除、節點改變、子節點改變等

@Watcher機制過程
客戶端向服務端註冊Watcher
服務端事件發生觸發Watcher
客戶端回調Watcher得到觸發事件情況

@Watcher機制特點
1)一次性觸發
事件發生觸發監聽,一個watcher event就會發送到設置監聽的客戶端
這種效果式一次性的,再發生同樣的事件不會觸發

2)事件封裝
Zookeeper使用WatchedEvent對象來封裝服務端事件並傳遞
WatchedEvent包含了每一個事件的三個基本屬性:
通知狀態(keeperState)
事件類型(eventType)
節點路徑(path)

3)event異步發送
Watcher的通知事件從服務端發送到客戶端是異步的

4)先註冊再觸發
Zookeeper中的Watcher機制必須客戶端先去服務端註冊監聽

同一個事件類型在不同的通知狀態中代表的含義不同,舉例如下表

其中連接狀態事件(type=None,path=null)不需要客戶端註冊,客戶端只要有需要直接處理就行了
 

@Shell客戶端設置Watcher
設置節點數據變動監聽
【例】get /aaa0000000001 watch

通過另一個客戶端更改節點數據
set /aaa0000000001 456789

此時設置監聽的節點收到的通知

再次通過另一個客戶端更改節點數據,設置監聽的節點不會收到通知

5. Zookeeper選舉機制

默認算法是FastLeaderElection,採用投票數大於半數則勝出的邏輯。

@相關概念
服務器ID
例如有三臺服務器,編號分別爲1、2、3
編號越大在選舉算法中的權重越大

選舉狀態
LOOKING    競選狀態
FOLLOWING  隨從狀態,同步leader狀態,參與投票
OBSERVING  觀察狀態,同步leader狀態,不參與投票
LEADING    領導者狀態

數據ID
服務器中存放的最新數據version
值越大說明數據越新,在選舉算法中數據越新權重越大

邏輯時鐘/投票次數
同一輪投票過程中的邏輯時鐘值是相同的
每投完一次票這個數據會增加

@全新集羣選舉
假設目前有5臺服務器,每臺服務器均沒有數據
編號分別是1、2、3、4、5,按編號依次啓動

規則:每個機器都給自己投票、投票數過半選舉結束

step1 服務器1啓動,給自己投票
然後發投票信息,由於其它機器還沒有啓動所以它收不到反饋信息
服務器1處於Looking狀態

step2 服務器2啓動,給自己投票
同時與服務器1交換信息
由於服務器2的編號大所以勝出
但此時投票數沒有大於半數,服務器1、2處於Looking狀態

step3 服務器3啓動,給自己投票
同時與服務器1、2交換信息
由於服務器2的編號大所以勝出
此時投票數正好大於半數,投票結束,服務器3成爲Leader,服務器1、2成爲Follower

step4 服務器4啓動,給自己投票
同時與服務器1、2、3交換信息
投票已結束,服務器4成爲Follower

step5 服務器5啓動,同服務器4

全新集羣選舉主要影響因素 -> 服務器編號

@非全新集羣選舉
對於運行正常的zookeeper集羣,中途有服務器down,需要重新選舉時,選舉過程就需要加入數據ID、服務器ID和邏輯時鐘

數據ID:數據新的version就大,數據每次更新都會更新version
服務器ID:配置的myid中的值,每個機器一個
邏輯時鐘:這個值從0開始遞增,每次選舉對應一個值。如果在同一次選舉中,這個值是一致的

選舉Leader標準如下
1)邏輯時鐘小的選舉結果被忽略,重新投票
2)同一邏輯時鐘後,數據id大的勝出
3)數據id相同的情況下,服務器id大的勝出

6. 典型應用

@數據發佈與訂閱(配置中心)
配置中心=> 發佈者將數據發佈到ZK節點上,供訂閱者動態獲取數據,實現配置信息的集中式管理和動態更新

應用在啓動的時候會主動來獲取一次配置,同時,在節點上註冊一個Watcher
配置有更新會實時通知到訂閱的客戶端,從而達到獲取最新配置信息的目的

例如,分佈式搜索服務中,索引的元信息和服務器集羣節點狀態存放在ZK的一些指定節點,供各個客戶端訂閱使用

注意:適合數據量很小的場景,這樣數據更新會比較快

@命名服務(Naming Service)
在分佈式系統中,通過使用命名服務,客戶端應用能夠根據指定名字來獲取資源或服務的地址,提供者等信息
被命名的實體通常可以是集羣中的機器、提供的服務地址、遠程對象等 => 可以統稱爲名字(Name)
通過調用ZK提供的創建節點的API,可以創建一個全局唯一的path => 可以作爲一個名稱

例如,阿里巴巴開源的分佈式服務框架Dubbo中使用Zookeeper來作爲其命名服務,維護全局的服務地址列表

@分佈式鎖
鎖服務可以分爲兩類,一個是保持獨佔,另一個是控制時序

1)保持獨佔
所有試圖獲取這個鎖的客戶端,最終只有一個可以成功獲得這把鎖

通常做法是把zk上的一個Znode看作一把鎖,通過create Znode的方式來實現
所有客戶端都去創建/distribute_lock節點(是臨時節點且非序列化),最終成功創建的那個客戶端擁有這把鎖

2)控制時序
所有視圖來獲取這個鎖的客戶端,最終都會被安排執行,只是有個全局時序

做法基本和前述相同,只是/distribute_lock已經預先存在
客戶端在它下面創建臨時有序節點
父節點/distribute_lock維持一份sequence,保證子節點創建的時序性

 

推薦閱讀:
我們能用zookeeper做什麼 https://blog.csdn.net/zhangzq86/article/details/80981234

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章