目錄
- 1.1、概述
- 1.2、選舉機制
- 1.2.1、選舉觸發條件
- 1.2.2、選舉規則
- 1.2.3、選舉過程詳解
- 1.3、數據同步機制
- 1.3.1、正常同步
- 1.3.2、宕機同步
- 1.4、客戶端常用命令
- 1.5、應用場景
- 1.5.1、配置管理
- 1.5.2、命令服務
- 1.5.3、分布式鎖服務
- 1.5.4、集群管理
- 1.5.5、分布式ID
- 1.5.6、分布式協調/通知
- 1.5.7、心跳檢測
1.1、概述
????????本文主要講述ZooKeeper工作機制與應用場景,關于ZooKeeper的核心概念、主要特征等內容請參考構建分布式系統的一致性基石之ZooKeeper簡介這篇博文。
1.2、選舉機制
????????ZooKeeper的選舉機制基于ZAB協議(ZooKeeper Atomic Broadcast),這是一種為分布式系統設計的原子廣播協議。其核心目標是快速選舉出Leader節點,并確保數據一致性。
1.2.1、選舉觸發條件
- 集群初始化時
????????所有節點啟動時均為LOOKING狀態,觸發首次選舉。 - 運行期間Leader故障時
????????Leader節點宕機或網絡中斷時,剩余節點重新選舉。
1.2.2、選舉規則
- ZXID(事務ID)優先
????????ZXID是64位整數,由epoch(任期)和counter(事務計數器)組成,數值越大表示數據越新,優先級更高。 - SID(服務器ID)次之
????????若ZXID相同,則SID(配置文件中的myid)較大的節點勝出。 - 過半原則
????????候選節點需獲得超過半數投票(即N/2 +1)才能成為Leader。
1.2.3、選舉過程詳解
????????假設有五臺服務器組成的Zookeeper集群,它們的id從1-5,在集群初次啟動時是沒有歷史數據,數據操作的事務ID也不存在,其選舉流程如下:
- 服務器1
????????服務器1啟動,發起投票,投票格式為(Zxid,ServerID),投出的票為(0,1),此時服務器1票數一票,不夠半數以上(3票),選舉無法完成,服務器1狀態保持為LOOKING。 - 服務器2
????????服務器2啟動,發起投票,投出的票為(0,2),服務器1和2分別投自己一票并交換選票信息:此時服務器1發現服務器2的ServerID比自己目前投票推舉的(服務器1)大,更改選票為推舉服務器2。此時服務器1票數0票,服務器2票數2票,沒有半數以上結果,選舉無法完成,服務器1,2狀態保持LOOKING。 - 服務器3
????????服務器3啟動,發起投票,投出的票為(0,3),此時服務器1和服務器2發現服務器3的ServerID比自己目前投票推舉的(服務器2)大,更改選票為推舉服務器3。此次投票結果:服務器1為0票,服務器2為0票,服務器3為3票。此時服務器3的票數已經超過半數,服務器3當選Leader。服務器1,2更改狀態為FOLLOWING,服務器3更改狀態為LEADING。 - 服務器4
????????服務器4啟動,發起投票。此時服務器1,2,3已經不是LOOKING狀態,不會更改選票信息。交換選票信息結果:服務器3為3票,服務器4為1票。此時服務器4服從多數,更改選票信息為服務器3,并更改狀態為FOLLOWING。 - 服務器5
????????服務器5啟動,同服務器4啟動過程類似。
Zookeeper集群的中每個服務器的數據都是一致的,除非網絡波動極大,才會導致Zxid不一致,故而每個服務器的Zxid一致。如果真的遇到Zxid不一致,那么最大的Zxid的服務器會自動當選leader,如果相當則按照上述規則進行選舉。
????????運行期間的Leader故障時,所有FOLLOWING節點切換為LOOKING狀態。此時觸發重新選舉Leader的過程,假設服務器3宕機時,服務器1的Zxid為100,服務器2的Zxid為101,服務器4的Zxid為104,服務器5的Zxid為105其選舉流程如下:
- 所有服務器給自己投票
????????此時服務器1、服務器2、服務器4、服務器5都為1票,服務器1、服務器2、服務器4、服務器5的狀態都為LOOKING。 - 投票比較
????????服務器1發現服務器5的Zxid最大,更改選票為推舉服務器5。服務器2發現服務器5的Zxid最大,更改選票為推舉服務器5。服務器4發現服務器5的Zxid最大,更改選票為推舉服務器5。 - 投票確認
????????服務器1為0票,服務器2為0票,服務器4為0票,服務器5為4票。此時服務器4的票數已經超過半數,服務器4當選Leader。服務器1,2、4更改狀態為FOLLOWING,服務器5更改狀態為LEADING。
1.3、數據同步機制
????????zookeeper 的數據同步是為了保證各節點中數據的一至性,同步時涉及兩個流程:
- 一個是正常的客戶端數據提交
- 一個是集群某個節點宕機在恢復后的數據同步
1.3.1、正常同步
????????當leader 接收客戶端寫請求,并同步給各個子節點的流程如下:
????????但實際情況要復雜的多,比如client 它并不知道哪個節點是leader 有可能寫的請求會發給follower ,由follower在轉發給leader進行同步處理,如下:
????????client向zk中的server發送寫請求到達follower,follower則會將該寫請求轉發給leader,leader將請求事務以proposal形式分發給follower;
????????當follower收到收到leader的proposal時,根據接收的先后順序處理proposal;
????????當Leader收到follower針對某個proposal過半的ack后,則發起事務提交,重新發起一個commit的proposal
????????follower收到commit的proposal后,記錄事務提交,并把數據更新到內存數據庫;
當寫成功后,反饋給client。
1.3.2、宕機同步
????????在集群運行過程當中如果有一個follower節點宕機,由于宕機節點沒過半,集群仍然能正常服務。當leader 收到新的客戶端請求,此時無法同步給宕機的節點。造成數據不一至。為了解決這個問題,當節點啟動時,第一件事情就是找當前的Leader,比對數據是否一至。不一至則開始同步,同步完成之后在進行對外提供服務。 如何比對Leader的數據版本呢,這里通過ZXID事務ID來確認。
ZXID是一個長度64位的數字,其中低32位是按照數字遞增,任何數據的變更都會導致,低32位的數字簡單加1。高32位是leader周期編號,每當選舉出一個新的leader時,新的leader就從本地事物日志中取出ZXID,然后解析出高32位的周期編號,進行加1,再將低32位的全部設置為0。這樣就保證了每次新選舉的leader后,保證了ZXID的唯一性而且是保證遞增的。
1.4、客戶端常用命令
- 啟動客戶端
zkCli.sh - 查看幫助
help - 查看當前znode所包含的內容
ls / - 創建節點
create /hello 18 - 創建短暫znode
create -e /haha tom - 創建帶序號znode
create -s /bigdata tom - 創建短暫帶序號
create -e -s /bigdata tom - 查看此節點的詳細信息
ls2 / - 獲得節點值監聽
get /hello watch - 監聽路徑
ls / watch - 修改znode數據
set /hello iiiii - 刪除節點
delete /hello - 遞歸刪除
rmr /delireba - 查看節點狀態信息
stat /
1.5、應用場景
????????ZooKeeper 是一個高可用的分布式數據管理與協調框架。基于對 ZAB 算法的實現, 該框架能夠很好地保證分布式環境中數據的一致性。也是基于這樣的特性,使得ZooKeeper 成為了解決分布式一致性問題的利器,其具有以下幾種典型的應用場景。
1.5.1、配置管理
????????zookeeper 提供了節點watch的功能,zookeeper 的 client(對外提供服務的 server)監控 zookeeper 上的節點(znode),當節點變動的時候,client 會收到變動事件和變動后的內容,基于 zookeeper 的這個特性,我們可以給服務器集群中的所有機器 (client)都注冊 watch 事件,監控特定 znode,節點中存儲部署代碼的配置信息, 需要更新代碼的時候,修改 znode 中的值,服務器集群中的每一臺 server 都會收到代碼更新事件,然后觸發調用,更新目標代碼。
????????現在有很多開源項目使用 Zookeeper 來維護配置,比如在 HBase 中,客戶端就是連接一個 Zookeeper,獲得必要的 HBase 集群的配置信息,然后才可以進一步操作。 還有在開源的消息隊列 Kafka 中,也使用 Zookeeper 來維護 broker 的信息。其原理如下:
1.5.2、命令服務
????????命名服務也是分布式系統中比較常見的一類場景。在分布式系統中,通過使用命名服務,客戶端應用能夠根據指定名字來獲取資源或服務的地址,提供者等信息。
????????注冊一個持久節點/service/business/what,他下面的每個子節點都是一個可用服務 , 保 存 了 服 務 的 地 址 端 口 等 信 息 , 服 務 調 用 者 通 過 zookeeper 獲 取 /service/business/what 所有子節點信息來得到可用的服務。
????????下面的節點都是臨時節點,服務器啟動的時候會過來注冊一個臨時節點,服務器掛掉之后或主動關閉之后,臨時節點會自動移除,這樣就可以保證使用者獲取的 what 服務都是可用的,而且可以動態的擴容縮容。
1.5.3、分布式鎖服務
????????一個集群是一個分布式系統,由多臺服務器組成。為了提高并發度和可靠性,多臺服務器上運行著同一種服務。當多個服務在運行時就需要協調各服務的進度,有時候需要保證當某個服務在進行某個操作時,其他的服務都不能進行該操作,即對該操作進行加鎖,如果當前機器掛掉后,釋放鎖并fail over 到其他的機器繼續執行該服務。
1.5.4、集群管理
????????一個集群有時會因為各種軟硬件故障或者網絡故障,出現某些服務器掛掉而被移除集群,而某些服務器加入到集群中的情況,zookeeper會將這些服務器加入/移出的情況通知給集群中的其他正常工作的服務器,以及時調整存儲和計算等任務的分配和執行等。此外zookeeper還會對故障的服務器做出診斷并嘗試修復。
1.5.5、分布式ID
????????在過去的單庫單表型系統中,通常可以使用數據庫字段自帶的auto_increment屬性來自動為每條記錄生成一個唯一的ID。但是分庫分表后,就無法在依靠數據庫的auto_increment屬性來唯一標識一條記錄了。此時我們就可以用zookeeper在分布式環境下生成全局唯一ID。做法如下:每次要生成一個新id時,創建一個持久順序節點,創建操作返回的節點序號,即為新id,然后把比自己節點小的刪除即可。
1.5.6、分布式協調/通知
????????ZooKeeper 中特有 Watcher 注冊與異步通知機制,能夠很好的實現分布式環境下不同機器,甚至不同系統之間的通知與協調,從而實現對數據變更的實時處理。使用方法通常是不同的客戶端都對 ZooKeeper 上同一個 ZNode 進行注冊,監聽ZNode 的變化(包括 ZNode 本身內容及子節點的),如果 ZNode 發生了變化,那么所有訂閱的客戶端都能夠接收到相應的 Watcher 通知,并做出相應的處理。 ZooKeeper 的分布式協調/通知,是一種通用的分布式系統機器間的通信方式。
1.5.7、心跳檢測
????????機器間的心跳檢測機制是指在分布式環境中,不同機器(或進程)之間需要檢測到彼此是否在正常運行,例如 A 機器需要知道 B 機器是否正常運行。在傳統的開 發中,我們通常是通過主機直接是否可以相互 PING 通來判斷,更復雜一點的話, 則會通過在機器之間建立長連接,通過 TCP 連接固有的心跳檢測機制來實現上層 機器的心跳檢測,這些都是非常常見的心跳檢測方法。 基于 ZooKeeper 的臨時節點的特性,可以讓不同的進程都在 ZooKeeper 的一個指定節點下創建臨時子節點,不同的進程直接可以根據這個臨時子節點來判斷對應 的進程是否存活。通過這種方式,檢測和被檢測系統直接并不需要直接相關聯,而是通過 ZooKeeper 上的某個節點進行關聯,大大減少了系統耦合。