Hadoop生態系統為開源屆提供很多優秀軟件,zookeeper便是其中一員。
前段時間項目中用到了zookeeper,主要是用作服務的注冊和發現使用方式類似阿里的dubbo。實際上zookeeper的功能不僅僅只有這些內容,它提供了一系列非常方便使用的功能,后面會提到。這篇文章僅僅是我個人的一點兒理解,如有錯誤煩請指正,以免給別人誤導。
1、zookeeper是什么
zookeeper的名字很有趣被稱為動物管理員,這是因為Hadoop生態系統中很多軟件的名字都是動物,hadoop本身就是小象的意思,還有hive小蜜蜂,pig。zookeeper作為一個分布式協調系統在hadhoop中被廣泛的應用,其中HBase默認帶有zookeeper。zookeeper主要功能有配置維護、分布式鎖、選舉、分布式隊列等,并且zookeeper本身可以是一個集群,提供了高可用性。這一切的功能都離不開zookeeper的數據模型。
2、zookeeper數據模型
zookeeper提供的命名服務看起來和一個unix的文件系統非常相似,下面是從官網復制的一張圖:
其中的每個節點稱為znode,每個znode節點既可以包含數據又可以包含子節點,由于zookeeper被定位為協調程序因此znode中的數據通常存儲的是非常小的數據,比如狀態信息,位置信息等等。znode中有一個很重要的概念——節點類型,znode有兩種類型的節點:臨時節點,永久節點。其中這兩種節點又分為有序和無序,重點講一下臨時節點,因為zk中很多基礎的功能都是基于臨時節點實現的,client在和zookeeper連接的時候兩者之間會建立起session,session的狀態由zookeeper服務端維護,臨時節點的特點是隨著session的超時服務端會將client建立的所有臨時節點移除,而永久節點即使客戶端退出節點也不會消失,同時臨時節點不能有子節點但是可以掛載數據。結合watcher機制可以實現非常豐富和靈活的功能。
3、zookeeper集群結構
zookeeper本身支持單機部署和集群部署,生產環境建議使用集群部署,因為集群部署不存在單點故障問題,并且zookeeper建議部署的節點個數為奇數個,只有超過一半的機器不可用整個zk集群才不可用。zookeeper集群中主要有兩個角色leader和flower,每個客戶端可以連接集群中的任何一個zookeeper節點,同時從其上面read信息,但是針對write操作,flower節點會轉發給leader,由leader負責原子廣播,從而保證集群中各個節點的數據一致性,zookeeper中規定只有當多余一半的節點同步完成整個write操作才算完成。也就是說可能會有少于一半的數據不是新數據,因此zookeeper中不是強一致性而是實現的最終一致性。但是客戶端可以使用sync來強制讀取最新的數據。
4、replaction
zookeeper中的高可用性是通過數據冗余和實現的,也就是一份數據存在多個節點中,zookeeper中要求同一份數據需要在超過一半的節點上存在,只有這樣才能實現對宕機數量的容忍度更高。zk建議配置奇數個節點,是因為在flower同步數據和進行leader選舉的時候都要求有超過一半完成或同意才算ok。舉例來說,假如有3個節點,至少需要有2個節點正常,就是容忍度為1(允許宕掉的節點數),有4個節點,至少需要有三個節點正常,容忍度同樣為1,多出來一個機器但是容忍度相同在任何時候看來都得不償失。因此zk建議部署奇數個節點,但這不是強制。另外再看一下為什么寫操作的時候要求至少有超過一半節點commit成功整體才成功,假如有2t+1個zk節點,也就是必須有t+1個節點commit成功才算成功,因為只有這種情況下才能達成至少有一個節點存有前后兩次的更新操作(兩次t+1節點至少會重復一個)。zookeeper使用zab算法實現數據的原子廣播,并且每次write會寫日志然后更新緩存,每個zk節點維護一個zxid,zxid是一個全局變量,隨著znode的每一次改變而遞增,當leader掛掉的時候,剩余的flower選擇zxid最大的節點作為新的leader,在新leader提供服務前還需要一次數據恢復,新leader只是擁有最多的數據,但不一定擁有最新的數據,因此leader和flower的數據需要同步到最新的狀態,通過合并的過程完成整個數據的恢復。
上圖5個zk節點允許兩個宕機,其他三個節點總是能恢復出來ABCDE。
5、Watch機制
zookeeper允許客戶端對znode節點或者節點中的數據設置監聽器,當znode改變的時候服務器觸發監聽,客戶端完成一個回調做自己需要處理的邏輯。zookeeper中的watch是一次性的,也就是當監聽觸發后,需要再次應用watcher,下次才能在收到變化的通知。exists,getData,getChildren接口都可以指定是否應用watcher,可以使用默認的watcher或者自定義watcher。觸發watcher的可以為create、delete、setData、setACL。
6、配置管理
如果是單機或者幾臺機器,當應用的配置項變更的時候,可能通過手動的方式去修改一下,但是假如一個集群中有成百上千個應用節點,如何才能保證快速無差錯的完成配置項的變更。zookeeper的出現可以輕松地解決這個問題
每個節點在zk上建立永久型znode并寫入配置項,然后監聽該節點下數據的變化,一旦其他客戶端修改了其中的數據,所有的監聽客戶端都會收到變更通知。
7、Leader選舉
zookeeper本身提供leader選舉機制,大概的思路是所有的節點創建臨時有序的znode然后監聽所有節點的變化情況,獲取最小序號和自己創建的序列作比較,如果自己為最小則當選為leader,當主動刪除自己創建的節點或者leader宕機后,臨時節點消失,該變化會被其他存活的節點獲取到從而觸發第二次的leader選舉,依次類推。實際上zookeeper提到的很多recipes curator都提供了很好的實現(除了兩階段提交),同時基于底層的zookeeper api開發應用需要考慮的東西很多,curator對這些都提供了封裝,所以如果要編寫zookeeper應用推薦使用curator。
leader應用的場景很廣泛,curator提供了兩種不同的選舉實現,一種是輪詢做leader,另外一種是永久獲取leader權直到退出,兩種選舉實現可以應用在不同的集群應用中。HBase中使用的是獲取leader的永久權。