Zookeeper詳細使用解析!分散式架構中的協調服務框架最佳選型實踐

攻城獅Chova發表於2021-05-18

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.叢集崩潰恢復正式完成

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監聽此埠)

相關文章