1 Zookeeper概述#
ZooKeeper是一個為分布式應(yīng)用所設(shè)計的分布的劫映、開源的協(xié)調(diào)服務(wù)乓旗,它主要是用來解決分布式應(yīng)用中經(jīng)常遇到的一些數(shù)據(jù)管理問題府蛇,簡化分布式應(yīng)用協(xié)調(diào)及其管理的難度,提供高性能的分布式服務(wù)
屿愚。ZooKeeper本身可以以Standalone模式安裝運行
汇跨,不過它的長處在于通過分布式ZooKeeper集群(一個Leader,多個Follower)妆距,基于一定的策略來保證ZooKeeper集群的穩(wěn)定性和可用性穷遂,從而實現(xiàn)分布式應(yīng)用的可靠性
。
在網(wǎng)上看到了一個很不錯的關(guān)于ZooKeeper的介紹:
顧名思義動物園管理員
娱据,他是拿來管大象(Hadoop) 蚪黑、 蜜蜂(Hive) 、 小豬(Pig) 的管理員吸耿, Apache Hbase和 Apache Solr 以及LinkedIn sensei 等項目中都采用到了 Zookeeper祠锣。ZooKeeper是一個分布式的酷窥,開放源碼的分布式應(yīng)用程序協(xié)調(diào)服務(wù)咽安,ZooKeeper是以Fast Paxos算法為基礎(chǔ),實現(xiàn)同步服務(wù)蓬推,配置維護和命名服務(wù)等分布式應(yīng)用
妆棒。
從介紹可以看出,ZooKeeper更傾向于對大型應(yīng)用的協(xié)同維護管理工作
沸伏。IBM則給出了IBM對ZooKeeper的認知: Zookeeper 分布式服務(wù)框架是 Apache Hadoop 的一個子項目糕珊,它主要是用來解決分布式應(yīng)用中經(jīng)常遇到的一些數(shù)據(jù)管理問題,如:統(tǒng)一命名服務(wù)毅糟、狀態(tài)同步服務(wù)红选、集群管理、分布式應(yīng)用配置項的管理等
姆另。
總之喇肋,我認為它的核心詞就是一個單詞,協(xié)調(diào)
迹辐。
2 Zookeeper特征#
在Hadoop權(quán)威指南中看到了關(guān)于ZooKeeper的一些核心特征蝶防,閱讀之后感覺總結(jié)的甚是精辟,在這里引用并總結(jié)明吩。
2.1 簡易##
ZooKeeper的最重要核心就是一個精簡文件系統(tǒng)
间学,提供一些簡單的操作以及附加的抽象(例如排序和通知)。
2.2 易表達##
ZooKeeper的原型是一個豐富的集合,它們是一些已建好的塊低葫,可以用來構(gòu)建大型的協(xié)作數(shù)據(jù)結(jié)構(gòu)和協(xié)議
详羡,例如:分布式隊列、分布式鎖以及一組對等體的選舉嘿悬。
2.3 高可用性##
ZooKeeper運行在一些集群上殷绍,被設(shè)計成可用性較高的,因此應(yīng)用程序可以依賴它鹊漠。ZooKeeper可以幫助你的系統(tǒng)避免單點故障主到,從而建立一個可靠的應(yīng)用程序
。
2.4 松散耦合##
ZooKeeper的交互支持參與者之間并不了解對方躯概。例如:ZooKeeper可以被當(dāng)做一種公共的機制登钥,使得進程彼此不知道對方的存在也可以相互發(fā)現(xiàn)并且交互,對等方可能甚至不是同步的娶靡。
這一特點我感覺最能體現(xiàn)在集群的部署啟動過程中牧牢。像Hadoop當(dāng)把配置文件寫好之后,然后運行啟動腳本姿锭,則251塔鳍,241,242中作為集群的虛擬機是同步啟動的呻此,也就是DataNode轮纫,NameNode,TaskTracker焚鲜,以及JobTracker的啟動并運行時在一次啟動過程中啟動的掌唾,就是運行一次啟動腳本文件,則都啟動起來忿磅。但是ZooKeeper的啟動過程卻不是這樣的糯彬。我在251,241葱她,242部署了ZooKeeper集群撩扒,并進行啟動,則啟動的過程是這樣的:首先ssh到251然后啟動吨些,這時候251的集群節(jié)點啟動起來搓谆,但是控制臺一直報錯,大概的含義就是沒有檢測到其他兩個結(jié)點锤灿。接著分別ssh到241挽拔,242,分別啟動集群中的剩下的結(jié)點但校,當(dāng)241啟動起來時螃诅,回到251查看,發(fā)現(xiàn)報錯的信息減少,意思是只差一個結(jié)點术裸。當(dāng)251倘是,241,242三臺服務(wù)器的結(jié)點全部啟動起來袭艺,則三臺的服務(wù)器的控制臺打印出正常的信息
搀崭。
2.5 一個庫##
ZooKeeper提供了一個開源的、共享的執(zhí)行存儲猾编,以及通用協(xié)作的方法瘤睹,分擔(dān)了每個程序員寫通用協(xié)議的負擔(dān)。隨著時間的推移答倡,人們可以增加和改進這個庫來滿足自己的需求轰传。
3 為什么使用Zookeeper#
記得在大約在2006年的時候Google出了Chubby來解決分布一致性的問題(distributed consensus problem)
,所有集群中的服務(wù)器通過Chubby最終選出一個Master Server 瘪撇,最后這個Master Server來協(xié)調(diào)工作
获茬。簡單來說其原理就是:在一個分布式系統(tǒng)中,有一組服務(wù)器在運行同樣的程序倔既,它們需要確定一個Value恕曲,以那個服務(wù)器提供的信息為主/為準(zhǔn),當(dāng)這個服務(wù)器經(jīng)過n/2+1的方式被選出來后
渤涌,所有的機器上的Process都會被通知到這個服務(wù)器就是主服務(wù)器 Master服務(wù)器佩谣,大家以他提供的信息為準(zhǔn)。很想知道Google Chubby中的奧妙歼捏,可惜人家Google不開源稿存,自家用。
但是在2009年3年以后沉默已久的Yahoo在Apache上推出了類似的產(chǎn)品ZooKeeper瞳秽,并且在Google原有Chubby的設(shè)計思想上做了一些改進,因為ZooKeeper并不是完全遵循Paxos協(xié)議
率翅,而是基于自身設(shè)計并優(yōu)化的一個2 phase commit
的協(xié)議练俐,如圖所示:
ZooKeeper跟Chubby一樣用來存放一些相互協(xié)作的信息(Coordination)
,這些信息比較小一般不會超過1M冕臭,在zookeeper中是以一種hierarchical tree的形式來存放腺晾,這些具體的Key/Value信息就store在tree node中
。
當(dāng)有事件導(dǎo)致node數(shù)據(jù)辜贵,例如:變更悯蝉,增加,刪除時托慨,Zookeeper就會調(diào)用 triggerWatch方法鼻由,判斷當(dāng)前的path來是否有對應(yīng)的監(jiān)聽者(watcher),如果有watcher,會觸發(fā)其process方法,執(zhí)行process方法中的業(yè)務(wù)邏輯
蕉世,如圖:
3.1 應(yīng)用實例##
ZooKeeper有了上述的這些用途蔼紧,讓我們設(shè)想一下,在一個分布式系統(tǒng)中有這這樣的一個應(yīng)用:
2個任務(wù)工廠(Task Factory)一主一從狠轻,如果從的發(fā)現(xiàn)主的死了以后奸例,從的就開始工作,他的工作就是向下面很多臺代理(Agent)發(fā)送指令向楼,讓每臺代理(Agent)獲得不同的賬戶進行分布式并行計算查吊,而每臺代理(Agent)中將分配很多帳號,如果其中一臺代理(Agent)死掉了湖蜕,那么這臺死掉的代理上的賬戶就不會繼續(xù)工作了菩貌。上述,出現(xiàn)了3個最主要的問題:
- Task Factory
主/從一致性的問題
重荠; - Task Factory
主/從心跳如何用簡單+穩(wěn)定 或者2者折中的方式實現(xiàn)
箭阶; - 一臺代理(Agent)死掉了以后,一部分的賬戶就無法繼續(xù)工作戈鲁,
需要通知所有在線的代理(Agent)重新分配一次帳號
仇参;
OK,讓我們想想ZooKeeper是不是能幫助我們?nèi)ソ鉀Q目前遇到的這3個最主要的問題呢婆殿?
- 任務(wù)工廠Task Factory都連接到ZooKeeper上诈乒,創(chuàng)建節(jié)點,設(shè)置對這個節(jié)點進行監(jiān)控婆芦,監(jiān)控方法例如:
event= new WatchedEvent(EventType.NodeDeleted, KeeperState.SyncConnected, "/TaskFactory");
這個方法的意思就是只要Task Factory與zookeeper斷開連接后怕磨,這個節(jié)點就會被自動刪除
。
原來主的任務(wù)工廠斷開了TCP連接消约,這個被創(chuàng)建的/TaskFactory節(jié)點就不存在了
肠鲫,而且另外一個連接在上面的Task Factory可以立刻收到這個事件(Event),知道這個節(jié)點不存在了或粮,也就是說主TaskFactory死了导饲。接下來另外一個活著的TaskFactory會再次創(chuàng)建/TaskFactory節(jié)點
,并且寫入自己的ip到znode里面氯材,作為新的標(biāo)記渣锦。此時Agents也會知道主的TaskFactory不工作了,為了防止系統(tǒng)中大量的拋出異常氢哮,他們將會先把自己手上的事情做完袋毙,然后掛起,
等待收到Zookeeper上重新創(chuàng)建一個/TaskFactory節(jié)點冗尤,收到 EventType.NodeCreated 類型的事件將會繼續(xù)工作
听盖。原來從的TaskFactory 將自己變成一個主TaskFactory
胀溺,當(dāng)系統(tǒng)管理員啟動原來死掉的主的TaskFactory,世界又恢復(fù)平靜了媳溺。如果一臺代理死掉月幌,其他代理他們將會先把自己手上的事情做完
,然后掛起悬蔽,向TaskFactory發(fā)送請求扯躺,TaskFactory會重新分配(sharding)帳戶到每個Agent上了
,繼續(xù)工作蝎困。
上述內(nèi)容录语,大致如圖所示:
4 Zookeeper基本知識#
4.1 層次化的名字空間##
ZooKeeper的整個名字空間的結(jié)構(gòu)是層次化的,和一般的Linux文件系統(tǒng)結(jié)構(gòu)非常相似禾乘,一顆很大的樹
澎埠。這也就是ZooKeeper的數(shù)據(jù)結(jié)構(gòu)情況。名字空間的層次由斜杠/來進行分割始藕,在名稱空間里面的每一個結(jié)點的名字空間唯一由這個結(jié)點的路徑來確定蒲稳。
每一個節(jié)點擁有自身的一些信息,包括:數(shù)據(jù)伍派、數(shù)據(jù)長度江耀、創(chuàng)建時間、修改時間等等
诉植。從這樣一類既含有數(shù)據(jù)祥国,又作為路徑表標(biāo)示的節(jié)點的特點中,可以看出晾腔,ZooKeeper的節(jié)點既可以被看做是一個文件舌稀,又可以被看做是一個目錄,它同時具有二者的特點
灼擂。為了便于表達壁查,今后我們將使用Znode來表示所討論的ZooKeeper節(jié)點
。
4.2 Znode##
Znode維護著數(shù)據(jù)缤至、ACL(access control list潮罪,訪問控制列表)、時間戳等交換版本號等數(shù)據(jù)結(jié)構(gòu)
领斥,它通過對這些數(shù)據(jù)的管理來讓緩存生效并且令協(xié)調(diào)更新。每當(dāng)Znode中的數(shù)據(jù)更新后它所維護的版本號將增加沃暗,這非常類似于數(shù)據(jù)庫中計數(shù)器時間戳的操作方式月洛。
另外Znode還具有原子性操作的特點
:命名空間中,每一個Znode的數(shù)據(jù)將被原子地讀寫孽锥。讀操作將讀取與Znode相關(guān)的所有數(shù)據(jù)嚼黔,寫操作將替換掉所有的數(shù)據(jù)细层。除此之外,每一個節(jié)點都有一個訪問控制列表唬涧,這個訪問控制列表規(guī)定了用戶操作的權(quán)限疫赎。
ZooKeeper中同樣存在臨時節(jié)點
。這些節(jié)點與session同時存在碎节,當(dāng)session生命周期結(jié)束捧搞,這些臨時節(jié)點也將被刪除。臨時節(jié)點在某些場合也發(fā)揮著非常重要的作用狮荔。
4.3 Watch機制##
Watch機制就和單詞本身的意思一樣胎撇,看≈呈希看什么晚树?具體來講就是某一個或者一些Znode的變化。官方給出的定義:一個Watch事件是一個一次性的觸發(fā)器雅采,當(dāng)被設(shè)置了Watch的數(shù)據(jù)發(fā)生了改變的時候爵憎,則服務(wù)器將這個改變發(fā)送給設(shè)置了Watch的客戶端,以便通知它們
婚瓜。
Watch機制主要有以下三個特點:
- 一次性的觸發(fā)器(one-time trigger)
當(dāng)數(shù)據(jù)改變的時候宝鼓,那么一個Watch事件會產(chǎn)生并且被發(fā)送到客戶端中。但是客戶端只會收到一次這樣的通知
闰渔,如果以后這個數(shù)據(jù)再次發(fā)生改變的時候席函,之前設(shè)置Watch的客戶端將不會再次收到改變的通知,因為Watch機制規(guī)定了它是一個一次性的觸發(fā)器
冈涧。
當(dāng)設(shè)置監(jiān)視的數(shù)據(jù)發(fā)生改變時茂附,該監(jiān)視事件會被發(fā)送到客戶端,例如督弓,如果客戶端調(diào)用了 getData("/znode1", true) 并且稍后 /znode1 節(jié)點上的數(shù)據(jù)發(fā)生了改變或者被刪除了营曼,客戶端將會獲取到 /znode1 發(fā)生變化的監(jiān)視事件,而如果 /znode1 再一次發(fā)生了變化愚隧,除非客戶端再次對 /znode1 設(shè)置監(jiān)視蒂阱,否則客戶端不會收到事件通知
。
- 發(fā)送給客戶端(Sent to the client)
這個表明了Watch的通知事件是從服務(wù)器發(fā)送給客戶端的狂塘,是異步的录煤,這就表明不同的客戶端收到的Watch的時間可能不同
,但是ZooKeeper有保證:當(dāng)一個客戶端在看到Watch事件之前是不會看到結(jié)點數(shù)據(jù)的變化的
荞胡。例如:A=3妈踊,此時在上面設(shè)置了一次Watch,如果A突然變成4了泪漂,那么客戶端會先收到Watch事件的通知廊营,然后才會看到A=4歪泳。
Zookeeper 客戶端和服務(wù)端是通過 Socket 進行通信的,由于網(wǎng)絡(luò)存在故障露筒,所以監(jiān)視事件很有可能不會成功地到達客戶端呐伞,監(jiān)視事件是異步發(fā)送至監(jiān)視者的
,Zookeeper 本身提供了保序性(ordering guarantee):即客戶端只有首先看到了監(jiān)視事件后慎式,才會感知到它所設(shè)置監(jiān)視的 znode 發(fā)生了變化
(a client will never see a change for which it has set a watch until it first sees the watch event). 網(wǎng)絡(luò)延遲或者其他因素可能導(dǎo)致不同的客戶端在不同的時刻感知某一監(jiān)視事件伶氢,但是不同的客戶端所看到的一切具有一致的順序
。
- 被設(shè)置Watch的數(shù)據(jù)(The data for which the watch was set)
這意味著 znode 節(jié)點本身具有不同的改變方式瞬捕。你也可以想象 Zookeeper 維護了兩條監(jiān)視鏈表:數(shù)據(jù)監(jiān)視和子節(jié)點監(jiān)視
(data watches and child watches) getData() and exists() 設(shè)置數(shù)據(jù)監(jiān)視
鞍历,getChildren() 設(shè)置子節(jié)點監(jiān)視
。 或者肪虎,你也可以想象 Zookeeper 設(shè)置的不同監(jiān)視返回不同的數(shù)據(jù)劣砍,getData() 和 exists() 返回 znode 節(jié)點的相關(guān)信息
,而 getChildren() 返回子節(jié)點列表
扇救。因此刑枝, setData() 會觸發(fā)設(shè)置在某一節(jié)點上所設(shè)置的數(shù)據(jù)監(jiān)視(假定數(shù)據(jù)設(shè)置成功)
,而一次成功的 create() 操作則會出發(fā)當(dāng)前節(jié)點上所設(shè)置的數(shù)據(jù)監(jiān)視以及父節(jié)點的子節(jié)點監(jiān)視
迅腔。一次成功的 delete() 操作將會觸發(fā)當(dāng)前節(jié)點的數(shù)據(jù)監(jiān)視和子節(jié)點監(jiān)視事件装畅,同時也會觸發(fā)該節(jié)點父節(jié)點的child watch
。
Zookeeper 中的監(jiān)視是輕量級的沧烈,因此容易設(shè)置掠兄、維護和分發(fā)。當(dāng)客戶端與 Zookeeper 服務(wù)器端失去聯(lián)系時锌雀,客戶端并不會收到監(jiān)視事件的通知蚂夕,只有當(dāng)客戶端重新連接后,若在必要的情況下腋逆,以前注冊的監(jiān)視會重新被注冊并觸發(fā)婿牍,對于開發(fā)人員來說 這通常是透明的
。只有一種情況會導(dǎo)致監(jiān)視事件的丟失惩歉,即:通過 exists() 設(shè)置了某個 znode 節(jié)點的監(jiān)視等脂,但是如果某個客戶端在此 znode 節(jié)點被創(chuàng)建和刪除的時間間隔內(nèi)與 zookeeper 服務(wù)器失去了聯(lián)系,該客戶端即使稍后重新連接 zookeeper服務(wù)器后也得不到事件通知
撑蚌。
4.4 ACL訪問控制列表##
這是另外一個和Linux操作系統(tǒng)非常相似的地方上遥,ZooKeeper使用ACL來控制對旗下Znode結(jié)點們的訪問
。ACL的實現(xiàn)和Linux文件系統(tǒng)的訪問權(quán)限十分類似:它通過設(shè)置權(quán)限為來表明是否允許對一個結(jié)點的相關(guān)內(nèi)容的改變
争涌。
但是與傳統(tǒng)Linux機制不太相同露该,一個結(jié)點的數(shù)據(jù)沒有類似“擁有者,組用戶第煮,其他用戶”的概念解幼,在ZooKeeper中,ACL通過設(shè)置ID以及與其關(guān)聯(lián)的權(quán)限來完成訪問控制的
包警。ACL的權(quán)限組成語法是:
(scheme:expression, perms)
前者表明設(shè)置的ID撵摆,逗號后面表示的是ID相關(guān)的權(quán)限,例如:
(ip:172.16.16.1,READ)
指明了IP地址為如上的用戶的權(quán)限為只讀害晦。
以下列舉以下ACL所具有的權(quán)限:
CREATE:表明你可以創(chuàng)建一個Znode的子結(jié)點特铝。
READ:你可以得到這個結(jié)點的數(shù)據(jù)以及列舉該結(jié)點的子結(jié)點情況。
WRITE:設(shè)置一個結(jié)點的數(shù)據(jù)壹瘟。
DELETE:可以刪除一個結(jié)點
ADMIN:對一個結(jié)點設(shè)置權(quán)限鲫剿。
5 Zookeeper部署#
ZooKeeper的部署方式主要有三種,單機模式稻轨、偽集群模式灵莲、集群模式
。其實剩下的兩種模式都是集群模式的特殊情況殴俱。
5.1 系統(tǒng)環(huán)境##
5.2 下載Zookeeper##
mkdir /home/taomk/zk 創(chuàng)建文件夾
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 配置環(huán)境變量##
export ZOOKEEPER_HOME=/home/taomk/zk/zookeeper346
export PATH=$PATH:$ZOOKEEPER_HOME/bin:$ZOOKEEPER_HOME/conf
5.4 ZooKeeper的單機模式部署##
ZooKeeper的單機模式通常是用來快速測試客戶端應(yīng)用程序的政冻,在實際過程中不可能是單機模式。單機模式的配置也比較簡單线欲。
-
編寫配置文件zoo.cfg:ZooKeeper的運行
默認是讀取zoo.cfg文件
里面的內(nèi)容的明场。
~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 的值李丰,它指向了一個目錄古拴,這個目錄在開始的時候需要為空
。下面是每個參數(shù)的含義:
tickTime :基本事件單元辅柴,以毫秒為單位
誉察。這個時間是作為 Zookeeper 服務(wù)器之間或客戶端與服務(wù)器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發(fā)送一個心跳踱讨。
dataDir :存儲內(nèi)存中數(shù)據(jù)庫快照的位置
魏蔗,顧名思義就是 Zookeeper 保存數(shù)據(jù)的目錄,默認情況下痹筛,Zookeeper 將寫數(shù)據(jù)的日志文件也保存在這個目錄里
莺治。
clientPort :這個端口就是客戶端連接 Zookeeper 服務(wù)器的端口
,Zookeeper 會監(jiān)聽這個端口帚稠,接受客戶端的訪問請求谣旁。
使用單機模式時用戶需要注意:這種配置方式下沒有 ZooKeeper 副本,所以如果 ZooKeeper 服務(wù)器出現(xiàn)故障滋早, ZooKeeper 服務(wù)將會停止
榄审。
- 啟動Zookeeper
~bin/zkServer.sh start zk0.cfg
zk的服務(wù)顯示為QuorumPeerMain:
~jps
5321 QuorumPeerMain
5338 Jps
查看運行狀態(tài):
~bin/zkServer.sh status zk0.cfg
JMX enabled by default
Using config: /home/taomk/zk/zookeeper346/bin/../conf/zk0.cfg
Mode: standalone
單節(jié)點的時,Mode會顯示為standalone杆麸。
- 停止ZooKeeper服務(wù)
~ 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實例。其實在企業(yè)中式不會存在的莱革,另外為了測試一個客戶端程序也沒有必要存在峻堰,只有在物質(zhì)條件比較匱乏的條件下才會存在的模式。集群偽分布模式就是在單機下模擬集群的ZooKeeper服務(wù)盅视,在一臺機器上面有多個ZooKeeper的JVM同時運行
捐名。
ZooKeeper的集群模式下,多個Zookeeper服務(wù)器在工作前會選舉出一個Leader
闹击,在接下來的工作中這個被選舉出來的Leader死了镶蹋,而剩下的Zookeeper服務(wù)器會知道這個Leader死掉了,在活著的Zookeeper集群中會繼續(xù)選出一個Leader
拇砰,選舉出Leader的目的是為了可以在分布式的環(huán)境中保證數(shù)據(jù)的一致性梅忌。
- 確認集群服務(wù)器的數(shù)量
由于ZooKeeper集群中,會有一個Leader負責(zé)管理和協(xié)調(diào)其他集群服務(wù)器除破,因此服務(wù)器的數(shù)量通常都是單數(shù)
牧氮,例如3,5瑰枫,7...等踱葛,這樣2n+1的數(shù)量的服務(wù)器就可以允許最多n臺服務(wù)器的失效
。
- 創(chuàng)建環(huá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 服務(wù)器的客戶端,而是 Zookeeper 服務(wù)器集群中連接到 Leader 的 Follower 服務(wù)器
)初始化連接時最長能忍受多少個心跳時間間隔數(shù)
盯另。當(dāng)已經(jīng)超過 10 個心跳的時間(也就是 tickTime)長度后 Zookeeper 服務(wù)器還沒有收到客戶端的返回信息性含,那么表明這個客戶端連接失敗≡Ч撸總的時間長度就是 10*2000=20 秒商蕴。
syncLimit
:這個配置項標(biāo)識 Leader 與 Follower 之間發(fā)送消息,請求和應(yīng)答時間長度芝发,最長不能超過多少個 tickTime 的時間長度
绪商,總的時間長度就是 5*2000=10 秒。
server.A=B:C:D
:其中 A 是一個數(shù)字辅鲸,表示這個是第幾號服務(wù)器格郁,就是集群模式下配置的myid文件所存放的數(shù)值;B 是這個服務(wù)器的 ip 地址;C 表示的是這個服務(wù)器與集群中的 Leader 服務(wù)器交換信息的端口例书;D 表示的是萬一集群中的 Leader 服務(wù)器掛了锣尉,需要一個端口來重新進行選舉,選出一個新的 Leader雾叭,而這個端口就是用來執(zhí)行選舉時服務(wù)器相互通信的端口
悟耘。如果是偽集群的配置方式,由于 B 都是一樣织狐,所以不同的 Zookeeper 實例通信端口號不能一樣,所以要給它們分配不同的端口號
筏勒。
由于三個服務(wù)都在同一臺電腦上移迫,因此這里要保證地址的唯一性,因此要特別注意IP地址和端口號不要互相沖突管行,以免影響程序的正確執(zhí)行厨埋。
3個節(jié)點的ZooKeeper集群配置完成,接下來我們的啟動服務(wù)捐顷。
- 啟動集群
~ 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
#查看節(jié)點狀態(tài)
~ 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
- 查看ZooKeeper物理文件目錄結(jié)構(gòu)
~ tree -L 3 /home/taomk/zk/zoo
5.6 ZooKeeper Distributed模式##
ZooKeeper分布式模式安裝(ZooKeeper集群)也比較容易荡陷,這里說明一下基本要點。
首先要明確的是迅涮,ZooKeeper集群是一個獨立的分布式協(xié)調(diào)服務(wù)集群
废赞,“獨立”的含義就是說,如果想使用ZooKeeper實現(xiàn)分布式應(yīng)用的協(xié)調(diào)與管理叮姑,簡化協(xié)調(diào)與管理唉地,任何分布式應(yīng)用都可以使用,這就要歸功于Zookeeper的數(shù)據(jù)模型(Data Model)和層次命名空間(Hierarchical Namespace)結(jié)構(gòu)
传透,在設(shè)計你的分布式應(yīng)用協(xié)調(diào)服務(wù)時耘沼,首要的就是考慮如何組織層次命名空間。
下面說明分布式模式的安裝配置朱盐,過程如下所示:
- 第一步:主機名稱到IP地址映射配置
ZooKeeper集群中具有兩個關(guān)鍵的角色:Leader和Follower
群嗤。集群中所有的結(jié)點作為一個整體對分布式應(yīng)用提供服務(wù),集群中每個結(jié)點之間都互相連接兵琳,所以狂秘,在配置的ZooKeeper集群的時候,每一個結(jié)點的host到IP地址的映射都要配置上集群中其它結(jié)點的映射信息
闰围。
例如赃绊,ZooKeeper集群中每個結(jié)點的配置,以slave-01為例羡榴,/etc/hosts內(nèi)容如下所示:
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出了問題传惠,系統(tǒng)會采用該算法重新選出一個Leader。因此稻扬,各個結(jié)點之間要能夠保證互相連接卦方,必須配置上述映射。
ZooKeeper集群啟動的時候泰佳,會首先選出一個Leader盼砍,在Leader election過程中,某一個滿足選舉算法的結(jié)點就能成為Leader逝她。
- 第二步:修改ZooKeeper配置文件
在其中一臺機器(slave-01)上浇坐,解壓縮zookeeper-3.3.4.tar.gz,修改配置文件conf/zoo.cfg黔宛,內(nèi)容如下所示:
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
- 第三步:遠程復(fù)制分發(fā)安裝文件
上面已經(jīng)在一臺機器slave-01上配置完成ZooKeeper近刘,現(xiàn)在可以將該配置好的安裝文件遠程拷貝到集群中的各個結(jié)點對應(yīng)的目錄下:
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/
- 第四步:設(shè)置myid
在我們配置的dataDir指定的目錄下面,創(chuàng)建一個myid文件臀晃,里面內(nèi)容為一個數(shù)字觉渴,用來標(biāo)識當(dāng)前主機,conf/zoo.cfg文件中配置的server.X中X為什么數(shù)字徽惋,則myid文件中就輸入這個數(shù)字案淋,例如:
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集群的每個結(jié)點上,執(zhí)行啟動ZooKeeper服務(wù)的腳本寂曹,如下所示:
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集群啟動的時候,每個結(jié)點都試圖去連接集群中的其它結(jié)點隆圆,先啟動的肯定連不上后面還沒啟動的漱挚,所以日志前面部分的異常是可以忽略的
。通過后面部分可以看到渺氧,集群在選出一個Leader后旨涝,最后穩(wěn)定了。其他結(jié)點可能也出現(xiàn)類似問題侣背,屬于正常白华。
6 Zookeeper命令行操作#
ZooKeeper命令行工具類似于Linux的shell環(huán)境,不過功能肯定不及shell啦贩耐,但是使用它我們可以簡單的對ZooKeeper進行訪問弧腥,數(shù)據(jù)創(chuàng)建,數(shù)據(jù)修改等操作潮太。
對于客戶端來說管搪,ZooKeeper是一個整體(ensemble)虾攻,連接到ZooKeeper集群實際上感覺在獨享整個集群的服務(wù),所以更鲁,你可以在任何一個結(jié)點上建立到服務(wù)集群的連接霎箍。
當(dāng)啟動 ZooKeeper 服務(wù)成功之后,輸入下述命令澡为,連接到 ZooKeeper 服務(wù):
~ bin/zkCli.sh –server 127.0.0.1:2181
連接成功后漂坏,系統(tǒng)會輸出 ZooKeeper 的相關(guān)環(huán)境以及配置信息,并在屏幕輸出“ Welcome to ZooKeeper ”等信息媒至。
命令行工具的一些簡單操作如下:
-
使用 ls 命令來查看當(dāng)前 ZooKeeper 中所包含的內(nèi)容
:
ls /
-
創(chuàng)建一個新的 znode
顶别,使用 create /zk myData 。這個命令創(chuàng)建了一個新的 znode 節(jié)點“ zk ”以及與它關(guān)聯(lián)的字符串:
create /zk "myData"
-
運行 get 命令來確認 znode
是否包含我們所創(chuàng)建的字符串:
get /zk
- 通過
set 命令來對 zk 所關(guān)聯(lián)的字符串進行設(shè)置
:
set /zk "zsl"
get /zk
-
znode 刪除
:
delete /zk
-
通過help打印命令行幫助
:
-
退出客戶端連接
:
quit
7 Java編程現(xiàn)實命令行操作#
- ZkDemo.java :
public class ZkDemo {
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// 創(chuàng)建一個與服務(wù)器的連接
ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 60000, new Watcher() {
// 監(jiān)控所有被觸發(fā)的事件
public void process(WatchedEvent event) {
System.out.println("EVENT:" + event.getType());
}
});
// 查看根節(jié)點
System.out.println("ls / => " + zk.getChildren("/", true));
// 創(chuàng)建一個目錄節(jié)點
if (zk.exists("/node", true) == null) {
zk.create("/node", "conan".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("create /node conan");
// 查看/node節(jié)點數(shù)據(jù)
System.out.println("get /node => " + new String(zk.getData("/node", false, null)));
// 查看根節(jié)點
System.out.println("ls / => " + zk.getChildren("/", true));
}
// 創(chuàng)建一個子目錄節(jié)點
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節(jié)點
System.out.println("ls /node => " + zk.getChildren("/node", true));
}
// 修改節(jié)點數(shù)據(jù)
if (zk.exists("/node", true) != null) {
zk.setData("/node", "changed".getBytes(), -1);
// 查看/node節(jié)點數(shù)據(jù)
System.out.println("get /node => " + new String(zk.getData("/node", false, null)));
}
// 刪除節(jié)點
if (zk.exists("/node/sub1", true) != null) {
zk.delete("/node/sub1", -1);
zk.delete("/node", -1);
// 查看根節(jié)點
System.out.println("ls / => " + zk.getChildren("/", true));
}
// 關(guān)閉連接
zk.close();
}
}
- pom.xml塘慕,maven配置文件:
<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>