序言:
文章內(nèi)容輸出來源:拉勾教育Java高薪訓練營。
本篇文章是學習課程中的一部分課后筆記
一、簡介
1、zookeeper 概述
一個開源分布式協(xié)調(diào)服務,分布式數(shù)據(jù)一致性解決方案(共享存儲)
可實現(xiàn) 數(shù)據(jù)訂閱/發(fā)布、負載均衡、命名服務、集群管理、分布式鎖、分布式隊列等功能
2、基本概念
-
集群角色
- leader :為客戶端提供讀和寫服務
- follower : 提供讀的服務,參與leader選舉,寫操作的過半寫成功策略
- observer : 提供讀的服務
會話(session)
客戶端和服務端之間的一個tcp長連接,通過這個連接,客戶端能夠心跳檢測與服務端保持有效會話,也能夠向服務端發(fā)送請求并接受響應,還能接收服務端的watch事件通知。-
數(shù)據(jù)節(jié)點(znode)
- 機器節(jié)點 : 集群的機器
- 數(shù)據(jù)節(jié)點 : 數(shù)據(jù)模型中的數(shù)據(jù)單元 , /app/path (內(nèi)存樹 znode tree 中的節(jié)點信息)
-
版本
一個stat 的數(shù)據(jù)結(jié)構(gòu),記錄znode的三個數(shù)據(jù)版本:- version (znode的版本)
- cversion (znode子節(jié)點的版本)
- aversion (znode 的ACL 版本)
-
watcher (事件監(jiān)聽器)
- 允許用戶在指定節(jié)點注冊watcher,在一些特定事件觸發(fā)的時候,zookeeper 服務端會將事件通知到感興趣的客戶端。
-
流程:客戶端向zookeeper服務器注冊的同時,會將watcher對象存儲在客戶端watcherManager中,當zookeeper觸發(fā)watcher事件后,會向客戶端發(fā)送通知,客戶端從watcherManager中取出對應的watcher 對象來執(zhí)行回調(diào)邏輯。
watcher.png
-
ACL
采用 ACL( Access Control Lists ) 策略進行權(quán)限控制:- create :創(chuàng)建子節(jié)點權(quán)限
- read :獲取節(jié)點數(shù)據(jù)&子節(jié)點列表權(quán)限
- write : 更新節(jié)點數(shù)據(jù)權(quán)限
- delete : 刪除子節(jié)點的權(quán)限
- admin :設(shè)置節(jié)點ACL的權(quán)限
create & delete 都是針對子節(jié)點的權(quán)限控制
通常使用"scheme:id:permission" 標識一個有效的acl信息。
權(quán)限模式(scheme)、授權(quán)對象(id)、權(quán)限(permission)

二、系統(tǒng)模型
1、zookeeper 數(shù)據(jù)模型

2、ZNode 的類型
-
持久性節(jié)點
- 節(jié)點被創(chuàng)建后會一直存在服務器中,直到刪除操作主動清楚
-
臨時性節(jié)點
- 生命周期和客戶端會話綁在一起,客戶端會話結(jié)束,節(jié)點會被刪除掉,不能創(chuàng)建子節(jié)點。
-
順序性節(jié)點
- 附加到持久性節(jié)點與臨時性節(jié)點的屬性
三、應用場景
1、數(shù)據(jù)發(fā)布/訂閱
- 一般有兩種設(shè)計模式:推(push) 和 拉(pull)
例:
-
配置存儲
將一些初始化配置信息存儲到zookeeper上,如:
配置信息.png - 配置獲取
集群中每臺機器在啟動初始化階段,首先都會從配置節(jié)點中讀取信息,同時,客戶端還需要在該配置節(jié)點注冊一個watcher監(jiān)聽,一旦發(fā)生節(jié)點數(shù)據(jù)變更,所有訂閱的客戶端都能得到通知。 - 配置更新
只需要對zookeeper上配置的節(jié)點內(nèi)容進行更新,就能將變化的數(shù)據(jù)通知到各個客戶端,客戶端同步獲取最新數(shù)據(jù)。
2、命名服務(全局唯一id分配機制)

生成唯一ID的基本步驟:
1、所有客戶端都會根據(jù)自己的任務類型,在指定的類型的任務下面通過調(diào)用create創(chuàng)建
一個順序節(jié)點。
2 、create()會返回一個完整的節(jié)點名。如"job-0000000003"
3、客戶端拿到完整的節(jié)點名后,拼接上type類型,"type2-job-0000000003",就可以是全局唯一的id了。
3、集群管理
zk的兩大特性:
- 客戶端如果對數(shù)據(jù)節(jié)點注冊watcher監(jiān)聽,那么當該數(shù)據(jù)節(jié)點的內(nèi)容或是其子節(jié)點列表發(fā)生變更時,zk服務器就會向訂閱的客戶端發(fā)送變更通知。
- 對在zk上創(chuàng)建的臨時節(jié)點,一旦客戶端與服務器之間的會話失效,那么臨時節(jié)點也會被自動刪除。
利用其兩大特性,就可以實現(xiàn)集群機器存活監(jiān)控系統(tǒng)。
若監(jiān)控系統(tǒng)在/clusterServers節(jié)點上注冊一個watcher監(jiān)聽,那么但凡進行動態(tài)的添加機器操作,就會在/clusterServers節(jié)點上創(chuàng)建一個臨時節(jié)點,這樣就能實時檢測機器的變動情況。
4、分布式鎖
- 排他鎖
- 如果事務T1對數(shù)據(jù)對象O1添加了排他鎖,那么在整個加鎖期間,只允許事務T1對O1進行讀取和更新操作,其他事務都不能對O1進行任何類型操作----直到T1釋放了排他鎖。
ZK實現(xiàn)排他鎖:
① 定義鎖
java中通過synchronized機制與jdk1.5提供的ReentrantLock。
zk通過定義數(shù)據(jù)節(jié)點,定義為一個鎖:

② 獲取鎖
客戶端通過create()來創(chuàng)建臨時節(jié)點,zk保證了最終只能一個客戶端創(chuàng)建成功,其他沒成功在該節(jié)點注冊一個watcher監(jiān)聽,實時監(jiān)聽lock節(jié)點的變更情況。
③ 釋放鎖
情況一:當獲取鎖的客戶端宕機,zk的臨時節(jié)點就會被移除。
情況二:正常執(zhí)行完業(yè)務邏輯后,客戶端會主動刪除自己創(chuàng)建的臨時節(jié)點。

-
共享鎖
- 如果事務T1對數(shù)據(jù)對象O1加上了共享鎖,那么當前事務只能對O1進行讀取操作,其他事務也只能對該數(shù)據(jù)對象加共享鎖——直到該對象上的所有共享鎖都被釋放。
排他鎖&共享鎖根本區(qū)別:
- 加了排他鎖,數(shù)據(jù)對象只對一個事務可見。
- 加了共享鎖,數(shù)據(jù)對象對所有事務可見。
① 定義鎖
創(chuàng)建臨時有序節(jié)點:
定義鎖.png② 獲取鎖
創(chuàng)建臨時有序節(jié)點,如果是讀請求添加R類似的標識,寫請求添加W類似標識。
ZK判斷讀寫順序:

③ 釋放鎖
與排他鎖釋放機制一樣。
- 羊群效應

當ZK的所有子節(jié)點都注冊watcher到host1時,當host1移除自己的共享鎖之后,除了host2產(chǎn)生影響外(序號最小,進行寫操作),其他機器都繼續(xù)等待。
大量watcher通知和子節(jié)點列表獲取兩個操作會重復運行,影響性能與網(wǎng)絡(luò)開銷。
優(yōu)化的邏輯核心:關(guān)注比自己序號小的那個相關(guān)節(jié)點的變更情況即可。

5、分布隊列
-
FIFO先入先出
類似一個全是寫操作的共享鎖:
FIFO.png
- Barrier:分布式屏障
對一個節(jié)點數(shù)據(jù)內(nèi)容賦值一個數(shù)字n代表barrier值,當字節(jié)點個數(shù)達到n后,才會打開barrier。
場景: 分布式并行計算,最終的合并計算需要基于很多并行計算的子結(jié)果來進行。
barrier.png
四、ZAB協(xié)議
1、ZAB概述
zookeeper Atomic Broadcast (原子消息廣播協(xié)議),支持崩潰恢復的原子廣播協(xié)議的分布式一致性算法。
2、ZAB核心
-
定義了對于那些會改變zk服務器數(shù)據(jù)狀態(tài)的事務請求的處理方式。
ZAB核心.png
3、崩潰恢復
leader服務器出現(xiàn)異常情況,ZAB進入崩潰恢復模式,同時選舉產(chǎn)生新的leader服務器。
當集群中已經(jīng)有過半的機器與該leader服務器完成狀態(tài)同步(數(shù)據(jù)同步)之后,ZAB協(xié)議就會退出崩潰恢復模式。
4、消息廣播(類似二階提交過程)
當集群中已經(jīng)有過半的follower服務器完成了和leader服務器的狀態(tài)同步,整個服務框架就可以進入消息廣播模式。
當新加入一臺機器,就會進入數(shù)據(jù)恢復模式,找到leader所在服務器,并與其進行數(shù)據(jù)同步,然后一起參與到消息廣播流程中去。







