#0 系列目錄#java
Zookeeper系列node
Zookeeper源碼編程
Zookeeper應用
#1 Zookeeper概述# ZooKeeper是一個爲分佈式應用所設計的分佈的、開源的協調服務,它主要是用來解決分佈式應用中常常遇到的一些數據管理問題,簡化分佈式應用協調及其管理的難度,提供高性能的分佈式服務
。ZooKeeper自己能夠以Standalone模式安裝運行
,不過它的長處在於經過分佈式ZooKeeper集羣(一個Leader,多個Follower),基於必定的策略來保證ZooKeeper集羣的穩定性和可用性,從而實現分佈式應用的可靠性
。
在網上看到了一個很不錯的關於ZooKeeper的介紹: 顧名思義動物園管理員
,他是拿來管大象(Hadoop) 、 蜜蜂(Hive) 、 小豬(Pig) 的管理員, Apache Hbase和 Apache Solr 以及LinkedIn sensei 等項目中都採用到了 Zookeeper。ZooKeeper是一個分佈式的,開放源碼的分佈式應用程序協調服務,ZooKeeper是以Fast Paxos算法爲基礎,實現同步服務,配置維護和命名服務等分佈式應用
。
從介紹能夠看出,ZooKeeper更傾向於對大型應用的協同維護管理工做
。IBM則給出了IBM對ZooKeeper的認知: Zookeeper 分佈式服務框架是 Apache Hadoop 的一個子項目,它主要是用來解決分佈式應用中常常遇到的一些數據管理問題,如:統一命名服務、狀態同步服務、集羣管理、分佈式應用配置項的管理等
。
總之,我認爲它的核心詞就是一個單詞,協調
。
#2 Zookeeper特徵# 在Hadoop權威指南中看到了關於ZooKeeper的一些核心特徵,閱讀以後感受總結的甚是精闢,在這裏引用並總結。
##2.1 簡易## ZooKeeper的最重要核心就是一個精簡文件系統
,提供一些簡單的操做以及附加的抽象(例如排序和通知)。
##2.2 易表達## ZooKeeper的原型是一個豐富的集合,它們是一些已建好的塊,能夠用來構建大型的協做數據結構和協議
,例如:分佈式隊列、分佈式鎖以及一組對等體的選舉。
##2.3 高可用性## ZooKeeper運行在一些集羣上,被設計成可用性較高的,所以應用程序能夠依賴它。ZooKeeper能夠幫助你的系統避免單點故障,從而創建一個可靠的應用程序
。
##2.4 鬆散耦合## ZooKeeper的交互支持參與者之間並不瞭解對方。例如:ZooKeeper能夠被當作一種公共的機制,使得進程彼此不知道對方的存在也能夠相互發現而且交互,對等方可能甚至不是同步的。
這一特色我感受最能體如今集羣的部署啓動過程當中。像Hadoop當把配置文件寫好以後,而後運行啓動腳本,則251,241,242中做爲集羣的虛擬機是同步啓動的,也就是DataNode,NameNode,TaskTracker,以及JobTracker的啓動並運行時在一次啓動過程當中啓動的,就是運行一次啓動腳本文件,則都啓動起來。可是ZooKeeper的啓動過程卻不是這樣的。我在251,241,242部署了ZooKeeper集羣,並進行啓動,則啓動的過程是這樣的:首先ssh到251而後啓動,這時候251的集羣節點啓動起來,可是控制檯一直報錯,大概的含義就是沒有檢測到其餘兩個結點。接着分別ssh到241,242,分別啓動集羣中的剩下的結點,當241啓動起來時,回到251查看,發現報錯的信息減小,意思是隻差一個結點。當251,241,242三臺服務器的結點所有啓動起來,則三臺的服務器的控制檯打印出正常的信息
。
##2.5 一個庫## ZooKeeper提供了一個開源的、共享的執行存儲,以及通用協做的方法,分擔了每一個程序員寫通用協議的負擔。隨着時間的推移,人們能夠增長和改進這個庫來知足本身的需求。
#3 爲何使用Zookeeper# 記得在大約在2006年的時候Google出了Chubby來解決分佈一致性的問題(distributed consensus problem)
,全部集羣中的服務器經過Chubby最終選出一個Master Server ,最後這個Master Server來協調工做
。簡單來講其原理就是:在一個分佈式系統中,有一組服務器在運行一樣的程序,它們須要肯定一個Value,以那個服務器提供的信息爲主/爲準,當這個服務器通過n/2+1的方式被選出來後
,全部的機器上的Process都會被通知到這個服務器就是主服務器 Master服務器,你們以他提供的信息爲準。很想知道Google Chubby中的奧妙,惋惜人家Google不開源,自家用。
可是在2009年3年之後沉默已久的Yahoo在Apache上推出了相似的產品ZooKeeper,而且在Google原有Chubby的設計思想上作了一些改進,由於ZooKeeper並非徹底遵循Paxos協議
,而是基於自身設計並優化的一個2 phase commit
的協議,如圖所示:
ZooKeeper跟Chubby同樣用來存放一些相互協做的信息(Coordination)
,這些信息比較小通常不會超過1M,在zookeeper中是以一種hierarchical tree的形式來存放,這些具體的Key/Value信息就store在tree node中
。
當有事件致使node數據,例如:變動,增長,刪除時,Zookeeper就會調用 triggerWatch方法,判斷當前的path來是否有對應的監聽者(watcher),若是有watcher,會觸發其process方法,執行process方法中的業務邏輯
,如圖:
##3.1 應用實例## ZooKeeper有了上述的這些用途,讓咱們設想一下,在一個分佈式系統中有這這樣的一個應用:
2個任務工廠(Task Factory)一主一從,若是從的發現主的死了之後,從的就開始工做,他的工做就是向下面不少臺代理(Agent)發送指令,讓每臺代理(Agent)得到不一樣的帳戶進行分佈式並行計算,而每臺代理(Agent)中將分配不少賬號,若是其中一臺代理(Agent)死掉了,那麼這臺死掉的代理上的帳戶就不會繼續工做了。上述,出現了3個最主要的問題:
主/從一致性的問題
;主/從心跳如何用簡單+穩定 或者2者折中的方式實現
;須要通知全部在線的代理(Agent)從新分配一次賬號
;OK,讓咱們想一想ZooKeeper是否是能幫助咱們去解決目前遇到的這3個最主要的問題呢?
event= new WatchedEvent(EventType.NodeDeleted, KeeperState.SyncConnected, "/TaskFactory");
這個方法的意思就是只要Task Factory與zookeeper斷開鏈接後,這個節點就會被自動刪除
。
原來主的任務工廠斷開了TCP鏈接,這個被建立的/TaskFactory節點就不存在了
,並且另一個鏈接在上面的Task Factory能夠馬上收到這個事件(Event),知道這個節點不存在了,也就是說主TaskFactory死了。
接下來另一個活着的TaskFactory會再次建立/TaskFactory節點
,而且寫入本身的ip到znode裏面,做爲新的標記。
此時Agents也會知道主的TaskFactory不工做了,爲了防止系統中大量的拋出異常,他們將會先把本身手上的事情作完,而後掛起,等待收到Zookeeper上從新建立一個/TaskFactory節點,收到 EventType.NodeCreated 類型的事件將會繼續工做
。
原來從的TaskFactory 將本身變成一個主TaskFactory
,當系統管理員啓動原來死掉的主的TaskFactory,世界又恢復平靜了。
若是一臺代理死掉,其餘代理他們將會先把本身手上的事情作完
,而後掛起,向TaskFactory發送請求,TaskFactory會從新分配(sharding)賬戶到每一個Agent上了
,繼續工做。
上述內容,大體如圖所示:
#4 Zookeeper基本知識# ##4.1 層次化的名字空間## ZooKeeper的整個名字空間的結構是層次化的,和通常的Linux文件系統結構很是類似,一顆很大的樹
。這也就是ZooKeeper的數據結構狀況。名字空間的層次由斜槓/來進行分割,在名稱空間裏面的每個結點的名字空間惟一由這個結點的路徑來肯定。
每個節點擁有自身的一些信息,包括:數據、數據長度、建立時間、修改時間等等
。從這樣一類既含有數據,又做爲路徑表標示的節點的特色中,能夠看出,ZooKeeper的節點既能夠被看作是一個文件,又能夠被看作是一個目錄,它同時具備兩者的特色
。爲了便於表達,從此咱們將使用Znode來表示所討論的ZooKeeper節點
。
##4.2 Znode## Znode維護着數據、ACL(access control list,訪問控制列表)、時間戳等交換版本號等數據結構
,它經過對這些數據的管理來讓緩存生效而且令協調更新。每當Znode中的數據更新後它所維護的版本號將增長,這很是相似於數據庫中計數器時間戳的操做方式。
另外Znode還具備原子性操做的特色
:命名空間中,每個Znode的數據將被原子地讀寫。讀操做將讀取與Znode相關的全部數據,寫操做將替換掉全部的數據。除此以外,每個節點都有一個訪問控制列表,這個訪問控制列表規定了用戶操做的權限。
ZooKeeper中一樣存在臨時節點
。這些節點與session同時存在,當session生命週期結束,這些臨時節點也將被刪除。臨時節點在某些場合也發揮着很是重要的做用。
##4.3 Watch機制## Watch機制就和單詞自己的意思同樣,看。看什麼?具體來說就是某一個或者一些Znode的變化。官方給出的定義:一個Watch事件是一個一次性的觸發器,當被設置了Watch的數據發生了改變的時候,則服務器將這個改變發送給設置了Watch的客戶端,以便通知它們
。
Watch機制主要有如下三個特色:
當數據改變的時候,那麼一個Watch事件會產生而且被髮送到客戶端中。可是客戶端只會收到一次這樣的通知
,若是之後這個數據再次發生改變的時候,以前設置Watch的客戶端將不會再次收到改變的通知,由於Watch機制規定了它是一個一次性的觸發器
。
當設置監視的數據發生改變時,該監視事件會被髮送到客戶端,例如,若是客戶端調用了 getData("/znode1", true) 而且稍後 /znode1 節點上的數據發生了改變或者被刪除了,客戶端將會獲取到 /znode1 發生變化的監視事件,而若是 /znode1 再一次發生了變化,除非客戶端再次對 /znode1 設置監視,不然客戶端不會收到事件通知
。
這個代表了Watch的通知事件是從服務器發送給客戶端的,是異步的,這就代表不一樣的客戶端收到的Watch的時間可能不一樣
,可是ZooKeeper有保證:當一個客戶端在看到Watch事件以前是不會看到結點數據的變化的
。例如:A=3,此時在上面設置了一次Watch,若是A忽然變成4了,那麼客戶端會先收到Watch事件的通知,而後纔會看到A=4。
Zookeeper 客戶端和服務端是經過 Socket 進行通訊的,因爲網絡存在故障,因此監視事件頗有可能不會成功地到達客戶端,監視事件是異步發送至監視者的
,Zookeeper 自己提供了保序性(ordering guarantee):即客戶端只有首先看到了監視事件後,纔會感知到它所設置監視的 znode 發生了變化
(a client will never see a change for which it has set a watch until it first sees the watch event). 網絡延遲或者其餘因素可能致使不一樣的客戶端在不一樣的時刻感知某一監視事件,可是不一樣的客戶端所看到的一切具備一致的順序
。
這意味着 znode 節點自己具備不一樣的改變方式。你也能夠想象 Zookeeper 維護了兩條監視鏈表:數據監視和子節點監視
(data watches and child watches) getData() and exists() 設置數據監視
,getChildren() 設置子節點監視
。 或者,你也能夠想象 Zookeeper 設置的不一樣監視返回不一樣的數據,getData() 和 exists() 返回 znode 節點的相關信息
,而 getChildren() 返回子節點列表
。所以, setData() 會觸發設置在某一節點上所設置的數據監視(假定數據設置成功)
,而一次成功的 create() 操做則會出發當前節點上所設置的數據監視以及父節點的子節點監視
。一次成功的 delete() 操做將會觸發當前節點的數據監視和子節點監視事件,同時也會觸發該節點父節點的child watch
。
Zookeeper 中的監視是輕量級的,所以容易設置、維護和分發。當客戶端與 Zookeeper 服務器端失去聯繫時,客戶端並不會收到監視事件的通知,只有當客戶端從新鏈接後,若在必要的狀況下,之前註冊的監視會從新被註冊並觸發,對於開發人員來講 這一般是透明的
。只有一種狀況會致使監視事件的丟失,即:經過 exists() 設置了某個 znode 節點的監視,可是若是某個客戶端在此 znode 節點被建立和刪除的時間間隔內與 zookeeper 服務器失去了聯繫,該客戶端即便稍後從新鏈接 zookeeper服務器後也得不到事件通知
。
##4.4 ACL訪問控制列表## 這是另一個和Linux操做系統很是類似的地方,ZooKeeper使用ACL來控制對旗下Znode結點們的訪問
。ACL的實現和Linux文件系統的訪問權限十分相似:它經過設置權限爲來代表是否容許對一個結點的相關內容的改變
。
可是與傳統Linux機制不太相同,一個結點的數據沒有相似「擁有者,組用戶,其餘用戶」的概念,在ZooKeeper中,ACL經過設置ID以及與其關聯的權限來完成訪問控制的
。ACL的權限組成語法是:
(scheme:expression, perms)
前者代表設置的ID,逗號後面表示的是ID相關的權限,例如:
(ip:172.16.16.1,READ)
指明瞭IP地址爲如上的用戶的權限爲只讀。
如下列舉如下ACL所具備的權限:
CREATE:代表你能夠建立一個Znode的子結點。 READ:你能夠獲得這個結點的數據以及列舉該結點的子結點狀況。 WRITE:設置一個結點的數據。 DELETE:能夠刪除一個結點 ADMIN:對一個結點設置權限。
#5 Zookeeper部署# ZooKeeper的部署方式主要有三種,單機模式、僞集羣模式、集羣模式
。其實剩下的兩種模式都是集羣模式的特殊狀況。
##5.1 系統環境##
##5.2 下載Zookeeper##
mkdir /home/taomk/zk 建立文件夾
cd /home/taomk/zk; wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz 下載
tar xvf zookeeper-3.4.6.tar.gz 解壓縮
mv zookeeper-3.4.6 zookeeper346 重命名
cd zookeeper346; ls -l
##5.3 配置環境變量##
export ZOOKEEPER_HOME=/home/taomk/zk/zookeeper346 export PATH=$PATH:$ZOOKEEPER_HOME/bin:$ZOOKEEPER_HOME/conf
##5.4 ZooKeeper的單機模式部署## ZooKeeper的單機模式一般是用來快速測試客戶端應用程序的,在實際過程當中不多是單機模式。單機模式的配置也比較簡單。
默認是讀取zoo.cfg文件
裏面的內容的。~mkdir /home/taomk/zk/zoo/zk0 ~cp conf/zoo_sample.cfg conf/zk0.cfg ~vim conf/zk0.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/home/conan/zoo/zk0 clientPort=2181
在zk0.cfg這個文件中,咱們須要指定 dataDir 的值,它指向了一個目錄,這個目錄在開始的時候須要爲空
。下面是每一個參數的含義:
tickTime :基本事件單元,以毫秒爲單位
。這個時間是做爲 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每一個 tickTime 時間就會發送一個心跳。
dataDir :存儲內存中數據庫快照的位置
,顧名思義就是 Zookeeper 保存數據的目錄,默認狀況下,Zookeeper 將寫數據的日誌文件也保存在這個目錄裏
。
clientPort :這個端口就是客戶端鏈接 Zookeeper 服務器的端口
,Zookeeper 會監聽這個端口,接受客戶端的訪問請求。
使用單機模式時用戶須要注意:這種配置方式下沒有 ZooKeeper 副本,因此若是 ZooKeeper 服務器出現故障, ZooKeeper 服務將會中止
。
~bin/zkServer.sh start zk0.cfg
zk的服務顯示爲QuorumPeerMain:
~jps 5321 QuorumPeerMain 5338 Jps
查看運行狀態:
~bin/zkServer.sh status zk0.cfg JMX enabled by default Using config: /home/taomk/zk/zookeeper346/bin/../conf/zk0.cfg Mode: standalone
單節點的時,Mode會顯示爲standalone。
~ bin/zkServer.sh stop zk0.cfg JMX enabled by default Using config: /home/taomk/zk/zookeeper346/bin/../conf/zk0.cfg Stopping zookeeper ... STOPPED
##5.5 ZooKeeper的僞集羣模式部署## 所謂 「僞分佈式集羣」 就是在,在一臺PC中,啓動多個ZooKeeper的實例。「徹底分佈式集羣」 是每臺PC,啓動一個ZooKeeper實例。其實在企業中式不會存在的,另外爲了測試一個客戶端程序也沒有必要存在,只有在物質條件比較匱乏的條件下才會存在的模式。集羣僞分佈模式就是在單機下模擬集羣的ZooKeeper服務,在一臺機器上面有多個ZooKeeper的JVM同時運行
。
ZooKeeper的集羣模式下,多個Zookeeper服務器在工做前會選舉出一個Leader
,在接下來的工做中這個被選舉出來的Leader死了,而剩下的Zookeeper服務器會知道這個Leader死掉了,在活着的Zookeeper集羣中會繼續選出一個Leader
,選舉出Leader的目的是爲了能夠在分佈式的環境中保證數據的一致性。
因爲ZooKeeper集羣中,會有一個Leader負責管理和協調其餘集羣服務器,所以服務器的數量一般都是單數
,例如3,5,7...等,這樣2n+1的數量的服務器就能夠容許最多n臺服務器的失效
。
~ mkdir /home/taomk/zk/zoo/zk1 ~ mkdir /home/taomk/zk/zoo/zk2 ~ mkdir /home/taomk/zk/zoo/zk3 #新建myid文件 ~ echo "1" > /home/taomk/zk/zoo/zk1/myid ~ echo "2" > /home/taomk/zk/zoo/zk2/myid ~ echo "3" > /home/taomk/zk/zoo/zk3/myid
修改
:dataDir,clientPort
增長
:集羣的實例,server.X,」X」表示每一個目錄中的myid的值
~ vim /home/taomk/zk/zookeeper346/conf/zk1.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/home/taomk/zk/zoo/zk1 clientPort=2181 server.1=127.0.0.1:2888:3888 server.2=127.0.0.1:2889:3889 server.3=127.0.0.1:2890:3890 ~ vim /home/taomk/zk/zookeeper346/conf/zk2.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/home/taomk/zk/zoo/zk2 clientPort=2182 server.1=127.0.0.1:2888:3888 server.2=127.0.0.1:2889:3889 server.3=127.0.0.1:2890:3890 ~ vim /home/taomk/zk/zookeeper346/conf/zk3.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/home/taomk/zk/zoo/zk3 clientPort=2183 server.1=127.0.0.1:2888:3888 server.2=127.0.0.1:2889:3889 server.3=127.0.0.1:2890:3890
initLimit
:這個配置項是用來配置 Zookeeper 接受客戶端(這裏所說的客戶端不是用戶鏈接 Zookeeper 服務器的客戶端,而是 Zookeeper 服務器集羣中鏈接到 Leader 的 Follower 服務器
)初始化鏈接時最長能忍受多少個心跳時間間隔數
。當已經超過 10 個心跳的時間(也就是 tickTime)長度後 Zookeeper 服務器尚未收到客戶端的返回信息,那麼代表這個客戶端鏈接失敗。總的時間長度就是 10*2000=20 秒。
syncLimit
:這個配置項標識 Leader 與 Follower 之間發送消息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度
,總的時間長度就是 5*2000=10 秒。
server.A=B:C:D
:其中 A 是一個數字,表示這個是第幾號服務器,就是集羣模式下配置的myid文件所存放的數值;B 是這個服務器的 ip 地址;C 表示的是這個服務器與集羣中的 Leader 服務器交換信息的端口;D 表示的是萬一集羣中的 Leader 服務器掛了,須要一個端口來從新進行選舉,選出一個新的 Leader,而這個端口就是用來執行選舉時服務器相互通訊的端口
。若是是僞集羣的配置方式,因爲 B 都是同樣,因此不一樣的 Zookeeper 實例通訊端口號不能同樣,因此要給它們分配不一樣的端口號
。
因爲三個服務都在同一臺電腦上,所以這裏要保證地址的惟一性,所以要特別注意IP地址和端口號不要互相沖突,以避免影響程序的正確執行。
3個節點的ZooKeeper集羣配置完成,接下來咱們的啓動服務。
~ bin/zkServer.sh start zk1.cfg ~ bin/zkServer.sh start zk2.cfg ~ bin/zkServer.sh start zk3.cfg ~ jps 5422 QuorumPeerMain 5395 QuorumPeerMain 5463 QuorumPeerMain 5494 Jps #查看節點狀態 ~ bin/zkServer.sh status zk1.cfg JMX enabled by default Using config: /home/taomk/zk/zookeeper346/bin/../conf/zk1.cfg Mode: follower ~ bin/zkServer.sh status zk2.cfg JMX enabled by default Using config: /home/taomk/zk/zookeeper346/bin/../conf/zk2.cfg Mode: leader ~ bin/zkServer.sh status zk3.cfg JMX enabled by default Using config: /home/taomk/zk/zookeeper346/bin/../conf/zk3.cfg Mode: follower
~ tree -L 3 /home/taomk/zk/zoo
##5.6 ZooKeeper Distributed模式## ZooKeeper分佈式模式安裝(ZooKeeper集羣)也比較容易,這裏說明一下基本要點。
首先要明確的是,ZooKeeper集羣是一個獨立的分佈式協調服務集羣
,「獨立」的含義就是說,若是想使用ZooKeeper實現分佈式應用的協調與管理,簡化協調與管理,任何分佈式應用均可以使用,這就要歸功於Zookeeper的數據模型(Data Model)和層次命名空間(Hierarchical Namespace)結構
,在設計你的分佈式應用協調服務時,首要的就是考慮如何組織層次命名空間。
下面說明分佈式模式的安裝配置,過程以下所示:
ZooKeeper集羣中具備兩個關鍵的角色:Leader和Follower
。集羣中全部的結點做爲一個總體對分佈式應用提供服務,集羣中每一個結點之間都互相鏈接,因此,在配置的ZooKeeper集羣的時候,每個結點的host到IP地址的映射都要配置上集羣中其它結點的映射信息
。
例如,ZooKeeper集羣中每一個結點的配置,以slave-01爲例,/etc/hosts內容以下所示:
192.168.0.179 slave-01 192.168.0.178 slave-02 192.168.0.177 slave-03
ZooKeeper採用一種稱爲Leader election的選舉算法。在整個集羣運行過程當中,只有一個Leader,其餘的都是Follower,若是ZooKeeper集羣在運行過程當中Leader出了問題,系統會採用該算法從新選出一個Leader。所以,各個結點之間要可以保證互相鏈接,必須配置上述映射。
ZooKeeper集羣啓動的時候,會首先選出一個Leader,在Leader election過程當中,某一個知足選舉算法的結點就能成爲Leader。
在其中一臺機器(slave-01)上,解壓縮zookeeper-3.3.4.tar.gz,修改配置文件conf/zoo.cfg,內容以下所示:
tickTime=2000 dataDir=/home/hadoop/storage/zookeeper clientPort=2181 initLimit=5 syncLimit=2 server.1=slave-01:2888:3888 server.2=slave-02:2888:3888 server.3=slave-03:2888:3888
上面已經在一臺機器slave-01上配置完成ZooKeeper,如今能夠將該配置好的安裝文件遠程拷貝到集羣中的各個結點對應的目錄下:
cd /home/hadoop/installation/ scp -r zookeeper-3.3.4/ hadoop@slave-02:/home/hadoop/installation/ scp -r zookeeper-3.3.4/ hadoop@slave-03:/home/hadoop/installation/
在咱們配置的dataDir指定的目錄下面,建立一個myid文件,裏面內容爲一個數字,用來標識當前主機,conf/zoo.cfg文件中配置的server.X中X爲何數字,則myid文件中就輸入這個數字,例如:
hadoop@slave-01:~/installation/zookeeper-3.3.4$ echo "1" > /home/hadoop/storage/zookeeper/myid hadoop@slave-02:~/installation/zookeeper-3.3.4$ echo "2" > /home/hadoop/storage/zookeeper/myid hadoop@slave-03:~/installation/zookeeper-3.3.4$ echo "3" > /home/hadoop/storage/zookeeper/myid
在ZooKeeper集羣的每一個結點上,執行啓動ZooKeeper服務的腳本,以下所示:
hadoop@slave-01:~/installation/zookeeper-3.3.4$ bin/zkServer.sh start hadoop@slave-02:~/installation/zookeeper-3.3.4$ bin/zkServer.sh start hadoop@slave-03:~/installation/zookeeper-3.3.4$ bin/zkServer.sh start
啓動的順序是slave-01>slave-02>slave-03,因爲ZooKeeper集羣啓動的時候,每一個結點都試圖去鏈接集羣中的其它結點,先啓動的確定連不上後面還沒啓動的,因此日誌前面部分的異常是能夠忽略的
。經過後面部分能夠看到,集羣在選出一個Leader後,最後穩定了。其餘結點可能也出現相似問題,屬於正常。
#6 Zookeeper命令行操做# ZooKeeper命令行工具相似於Linux的shell環境,不過功能確定不及shell啦,可是使用它咱們能夠簡單的對ZooKeeper進行訪問,數據建立,數據修改等操做。
對於客戶端來講,ZooKeeper是一個總體(ensemble),鏈接到ZooKeeper集羣實際上感受在獨享整個集羣的服務,因此,你能夠在任何一個結點上創建到服務集羣的鏈接。
當啓動 ZooKeeper 服務成功以後,輸入下述命令,鏈接到 ZooKeeper 服務:
~ bin/zkCli.sh –server 127.0.0.1:2181
鏈接成功後,系統會輸出 ZooKeeper 的相關環境以及配置信息,並在屏幕輸出「 Welcome to ZooKeeper 」等信息。
命令行工具的一些簡單操做以下:
使用 ls 命令來查看當前 ZooKeeper 中所包含的內容
:ls /
建立一個新的 znode
,使用 create /zk myData 。這個命令建立了一個新的 znode 節點「 zk 」以及與它關聯的字符串:create /zk "myData"
運行 get 命令來確認 znode
是否包含咱們所建立的字符串:get /zk
set 命令來對 zk 所關聯的字符串進行設置
:set /zk "zsl" get /zk
znode 刪除
:delete /zk
經過help打印命令行幫助
:退出客戶端鏈接
:quit
#7 Java編程現實命令行操做#
public class ZkDemo { public static void main(String[] args) throws IOException, KeeperException, InterruptedException { // 建立一個與服務器的鏈接 ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 60000, new Watcher() { // 監控全部被觸發的事件 public void process(WatchedEvent event) { System.out.println("EVENT:" + event.getType()); } }); // 查看根節點 System.out.println("ls / => " + zk.getChildren("/", true)); // 建立一個目錄節點 if (zk.exists("/node", true) == null) { zk.create("/node", "conan".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println("create /node conan"); // 查看/node節點數據 System.out.println("get /node => " + new String(zk.getData("/node", false, null))); // 查看根節點 System.out.println("ls / => " + zk.getChildren("/", true)); } // 建立一個子目錄節點 if (zk.exists("/node/sub1", true) == null) { zk.create("/node/sub1", "sub1".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println("create /node/sub1 sub1"); // 查看node節點 System.out.println("ls /node => " + zk.getChildren("/node", true)); } // 修改節點數據 if (zk.exists("/node", true) != null) { zk.setData("/node", "changed".getBytes(), -1); // 查看/node節點數據 System.out.println("get /node => " + new String(zk.getData("/node", false, null))); } // 刪除節點 if (zk.exists("/node/sub1", true) != null) { zk.delete("/node/sub1", -1); zk.delete("/node", -1); // 查看根節點 System.out.println("ls / => " + zk.getChildren("/", true)); } // 關閉鏈接 zk.close(); } }
<dependencies> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.6</version> <exclusions> <exclusion> <groupId>javax.jms</groupId> <artifactId>jms</artifactId> </exclusion> <exclusion> <groupId>com.sun.jdmk</groupId> <artifactId>jmxtools</artifactId> </exclusion> <exclusion> <groupId>com.sun.jmx</groupId> <artifactId>jmxri</artifactId> </exclusion> </exclusions> </dependency> </dependencies>