Zookeeper概念
- Zookeeper是分布式協調服務,用于管理大型主機,在分布式環境中協調和管理服務是很複雜的過程,Zookeeper通過簡單的架構和API解決了這個問題
Zookeeper實作分布式鎖
分布式鎖三要素:
加鎖
解鎖
鎖逾時
- Zookeeper資料結構類似樹結構,由節點Znode組成
- Znode分為四種類型:
- 持久節點(PERSISTENT): 預設節點類型,建立節點的用戶端與Zookeeper斷開連接配接後,節點依舊存在
- 持久節點順序節點(PERSISTENT_SEQUENTIAL): 持久節點順序節點就是在建立持久節點時,Zookeeper根據建立節點的時間順序給節點進行編号
- 臨時節點(EPHEMERAL): 建立節點的用戶端與Zookeeper斷開連接配接後,臨時節點會被删除
- 臨時節點順序節點(EPHEMERAL_SEQUENTIAL): 臨時節點順序節點就是在建立臨時節點時,Zookeeper根據建立節點的時間順序給節點進行編号
- 應用Zookeeper的臨時順序節點,實作分布式鎖
Zookeeper與Redis分布式鎖比較:
分布式鎖 | Zookeeper | Redis |
---|---|---|
優點 | 1.有封裝好的架構,容易實作 2.有等待鎖隊列,提升搶鎖的效率 | Set和Del指令性能高 |
缺點 | 添加和删除節點性能低 | 1.實作複雜,需要考慮原子性,誤删,鎖逾時問題 2.沒有等待鎖的隊列,隻能用戶端自旋來等鎖,效率低 |
Zookeeper的資料模型
- 類似資料結構中的樹,檔案系統中的目錄
- Zookeeper的資料存儲基于節點Znode
- Znode的引用方式是路徑引用,每一個Znode節點擁有唯一的路徑
Znode中的元素
- data: Znode存儲的資料資訊
- ACL: 記錄Znode的通路權限,即哪些程序和IP可以通路本節點
- stat: Znode的各種中繼資料(資料的資料)
- child: 目前節點的子節點引用
Zookeeper的應用場景是讀多寫少的應用場景:Znode不用來存儲大規模的業務資料,用于存儲少量的狀态和配置資訊(Znode存儲資料不能超過1MB)
Zookeeper基本操作
- 建立節點:create
- 删除節點:delete
- 判斷節點是否存在:exists
- 獲得一個節點的資料:getData
- 設定一個節點的資料:setData
- 擷取節點下的所有子節點:getChildren
exists,getData,getChildren屬于讀操作,Zookeeper用戶端在請求讀操作時,可以選擇是否設定watch
Zookeeper事件通知
- Watch可以了解成注冊在特定Znode上的觸發器
- 當Znode發生改變的時候,調用create,delete,setData方法,将會觸發Znode上注冊的對應事件,請求的Watch的用戶端會接收到異步通知
- Zookeeper事件通知的互動過程:
- 用戶端調用getData方法,watch的參數是true,服務端接收到請求,傳回節點資料,在對應的Hash表中插入被Watch的Znode路徑以及Watcher清單
- 當被Watch的Znode删除,服務端會查找Hash表,找到該Znode對應的所有Watcher,異步通知用戶端,并且删除Hash表中對應的key-value
Zookeeper的一緻性
- Zookeeper Service叢集是一主多從結構
- 在更新資料時,首先更新到主伺服器,再同步到從伺服器
- 在讀資料時,直接讀取任意節點
- 采用ZAB協定,為了保證主從節點資料的一緻性
ZAB協定
- ZAB(Zookeeper Automic Broadcast): 解決Zookeeper叢集崩潰恢複,主從資料同步問題
- ZAB三種節點狀态:
- Looking:選舉狀态
- Following:Following節點(從節點)所處的狀态
- Leading:Leading(主節點)所處的狀态
- 最大ZXID: 節點本地的最新事務編号,包含epoch和計數兩部分
ZAB叢集崩潰恢複
- 當Zookeeper的主節點伺服器當機後,叢集就會進行崩潰恢複,分成三個階段:
- Leader election(選舉階段):
- 叢集中的節點處于Looking狀态,各自向其它節點發起投票,投票當中包含自己伺服器的ID和最新事務ID(ZXID)
- 節點用自身的ZXID和其它節點收到的ZXID作比較,如果發現其它節點的ZXID比自身大,即資料比自己新,就重新發起投票,投票給目前已知最大ZXID所屬節點
- 每次投票後,伺服器都會統計投票數量,判斷是否某個節點得到半數以上的投票,這樣的節點将會成為準Leader,狀态變為Leading,其它節點狀态變為Following
- Discovery(發現階段):
- 在從節點發現最新的ZXID和事務日志,目的是為了防止在意外情況,選舉産生多個Leader
- Leader接收所有Follower發送的最新的epoch值,Leader從中選出最大的epoch,基于此值+1,生成新的epoch分發給各個Follower
- 各個Follower接收到最新的epoch,傳回ACK(響應碼)給Leader,帶上各自最大的ZXID和曆史事務日志,Leader選出最大的ZXID,并更新自身曆史日志
- Synchronization(同步階段):
- 将Leader收集得到的最新曆史事務日志,同步給叢集中的所有Follower,隻有當半數Follower同步成功,這個準Leader才能成為正式Leader.叢集崩潰恢複正式完成
- Leader election(選舉階段):
ZAB主從資料同步
- Broadcast
Zookeeper正常情況下更新資料的時候,由Leader廣播到所有的Follower:
- 用戶端發出寫入資料請求給任意的Follower
- Follower把寫入資料請求轉發給Leader
- Leader采取二階段送出方式:(先保留送出日志,再送出資料)先發送Propose廣播給Follower
- Follower接收到Propose消息,寫入日志成功後,傳回ACK消息給Leader
- Leader接收到半數以上的ACK消息,傳回成功給用戶端,并且廣播commit請求給Follower
資料一緻性:
強一緻性
弱一緻性
順序一緻性:Zookeeper,依靠事務ID和版本号,保證資料的更新和讀取是有序的
Zookeeper應用場景
- 分布式鎖: 應用Zookeeper的臨時順序節點,實作分布式鎖
- 服務注冊與發現: 利用Znode和Watcher,實作分布式服務注冊與發現,如Dubbo
- 共享配置和狀态資訊: Redis的分布式解決方案Codls,利用Zookeeper存放資料路由表和codls-proxy節點元資訊,同時colds-config發起的指令都會通過Zookeeper同步到各個存活的codls-proxy
- 高可用實作: Kafka,HBase,Hadoop都依靠Zookeeper同步節點資訊,實作高可用
基于Docker建立Zookeeper
1.建立docker-compose.yml
zoo:
image: zookeeper
restart: always
hostname: zoo
ports:
- 2181:2181
environment:
- ZOO_MY_ID: 1
- ZOO_SERVER: server.1(id)=zoo(IP):2888:3888
2.執行docker-compose up -d
Zookeeper三種工作模式
- 單機模式: 存在單點故障
- 叢集模式: 在多台伺服器上部署Zookeeper叢集
- 僞叢集模式: 在同一台伺服器上運作多個Zookeeper執行個體,仍然有單點故障問題,其中配置的端口号要錯開
Zookeeper三種端口号
- 2181: 用戶端連接配接Zookeeper叢集使用的監聽端口号
- 3888: 選舉Leader使用
- 2888: 叢集内機器通訊使用(Leader和Follower之間資料同步使用的端口号,Leader監聽此端口)