1、ZooKeeper是什麼?
ZooKeeper 是一個開源的分布式服務架構Hadoop的一個子項目,Zookeeper 實作諸如資料釋出/訂閱、統一命名服務、分布式協調/通知、配置管理、分布式鎖和分布式隊列等功能,通俗的講zookeeper是一個支援增删查改的類似檔案系統特點的資料庫,按照規則去給節點配置設定任務。zookeeper底層實作了存儲檔案和通知回調功能它的資料結構類似于一個标準的檔案系統,相比較檔案系統zk的每個節點都可以存儲資料,但是大小限制為1M。通常我們在使用dubbo的時候會建議使用zookeeper作為注冊中心,也可以用redis,eureka作為注冊中心,當然我隻用過zookeeper,dubbo相當于搭載一個服務架構,zookeeper則是服務注冊的中心。

zk的資料結構
zk服務的配置檔案
上面提到zk就是一個資料庫那麼它的資料就儲存在dataDir中,上圖中的配置是一個叢集配置,有server1,server2,server3三台伺服器,我們這裡是一個僞叢集(同一台機器啟動三個server),我們可以看到localhost:A:B,其中licalhost是我們的服務ip,A是專門用來選舉的端口,B叢集進行通信端口,clientPort是對client提供服務的端口。
名詞解釋:
資料釋出/訂閱:初始化節點的時候在服務節點注冊一個資料變更Watcher ,對節點進行變更操作的時候會将資料通知到用戶端,用戶端接受到變更通知後會重新讀取變更後的資料。
統一命名服務:獲得全局的唯一名稱,還可以借助znode順序節點的特性産生的節點都會傳回順序編号,在按照給定的名字,生成具有特殊含義的統一名字,所有用戶端可建立同一個名字的不同順序節點。
2、伺服器的角色?以及狀态
伺服器有Leader、Follower、Observer三種角色 ,其中Leader是叢集内部各個服務的排程者,保證了事務處理的順序性。Follower參與Proposal的投票,參與Leader選舉投票,處理用戶端的非事務請求,轉發事務請求(增删改,資料變更的操作)給Leader伺服器。Observer不參與投票,在不參與叢集事務能力的基礎上提升叢集的非事務處理能力。
伺服器的狀态分别為LOOKING(認為進群中伺服器沒有Leader尋找Leader的狀态)、FOLLOWING(伺服器角色是Follower的狀态)、LEADING(伺服器角色是 Leader的狀)、OBSERVING(伺服器角色是Observer的狀态)。
上司者選舉發生的節點有Leader挂掉的時候,叢集伺服器啟動的時候,Follower挂掉後Leader發現沒有過半的Follower跟随了,這三種情況會觸發上司者選舉。
3、zookeeper如何解決資料一緻性問題?
zookeeper server的啟動過程經曆了什麼。
若要了解zookeepr如何解決資料一緻性,zookeeper其實想達到的是強一緻性,但是最終達到的是最終一緻性,首先我們了解下什麼是CAP?這個大家自行百度,ZK遵循的是CP原則,犧牲了可用性,滿足了強一緻性。如下圖資料庫A 的資料進行了變更為2後,在步驟2進行讀取的時候不能讀取到的是1,那麼要求資料庫之間同步非常迅速或者在步驟2上加上鎖待資料同步完成後再讀取到結果.
強一緻性的例子
我們來大緻跟下源碼中的選舉流程我用的是git上的3.6.1的版本,找到zkServer.sh
找到守護程序的啟動腳本
找到參數中ZOOMAIN="org.apache.zookeeper.server.quorum.QuorumPeerMain"對應的這個類就是你檢視源碼服務的入口了。
在入口main方法中有一個初始化方法,main.initializeAndRun(args);這個方法進入以後圖中标紅的是進入叢集模式的方法,我們來看這個方法。
判斷為叢集模式
進入方法之後你會看到一堆set,讀取配置檔案值到QuorumPeer這個對象中呢,然後是對象的start,在啟動的時候就進行了調用選舉方法。
大家想一下zookeeper為何選擇奇數伺服器?
這個要從zookeeper的過半機制說起,假如6台機器隻最大允許叢集中宕掉2台機器,5 台機器也是允許當機兩台,從資源利用的角度是以建議選擇奇數台伺服器.
标紅的這塊為//投票決定方式,預設超過半數就通過
标紅的為leader選舉方法
預設electionAlgorithm為3
在FastLeaderElection類中lookForLeader方法的case looking 條件下進行投票選舉。private boolean totalOrderPredicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch)将收到的對方的投票與目前自己的投票對比,判斷對方的投票是否優于自己的投票。
totalOrderPredicate
隻要目前伺服器狀态為LOOKING,進入循環,不斷地讀取其它Server發來的通知、進行比較、更新自己的投票、發送自己的投票、統計投票結果,直到leader選出或出錯退出。
選舉比重參數
①Serverid:伺服器ID比如有三台伺服器,編号分别是1,2,3。編号越大在選擇算法中的權重越大。
②Zxid:事務日志id,事務請求每次就會生成一條事務日志,伺服器中存放的最大資料ID.值越大說明資料越新,在選舉算法中資料越新權重越大。
③Epoch:邏輯時鐘,或者叫投票的次數,同一輪投票過程中的邏輯時鐘值是相同的。每投完一次票這個資料就會增加,然後與接收到的其它伺服器傳回的投票資訊中的數值相比
叢集啟動投票流程
①每個Server會發出一個投票,是以對于Server1,Server2和Server3來說,都會将自己作為Leader伺服器來進行投票,每次投票包含最基本的元素有:所推舉的伺服器的myid和zxid,我們以(myid,zxid)的形式來表示,即Server1的投票為(1,0),Server2的投票為(2,0),然後各自将這個投票發給叢集中其他所有機器。
② 接收來自各個伺服器的投票,判斷該投票的有效性,包括檢查是否是本輪投票,是否來自LOOKING狀态的伺服器。
③ pk投票,在接收到來自其他伺服器的投票後,針對每一個投票,伺服器都需要将别人的投票和自己的投票進行PK:
- 優先檢查zxid,zxid比較大的伺服器優先作為Leader。
- 如果zxid相同的話,那麼就比較myid,myid比較大的伺服器作為Leader伺服器。結果Server1{(2,0),(2,0)},Server2{(2,0),2,0)}将票投給了Server2,那麼Server3也就直接跟随投給了Sever2,最終确定了Leader。
作者:宜信技術學院 王巧敏