一荠列、什么是 ZooKeeper
ZooKeeper 到底是什么沫换,為什么它在分布式系統(tǒng)里有著如此無(wú)可替代的地位臭蚁?
其實(shí)學(xué)任何一項(xiàng)技術(shù),首先都要弄明白,為什么需要這項(xiàng)技術(shù)垮兑。
例如為了解決大數(shù)據(jù)存儲(chǔ)問(wèn)題冷尉,因此有了 HDFS;為了解決大數(shù)據(jù)計(jì)算問(wèn)題系枪,因此有了 MapReduce雀哨;為了簡(jiǎn)化 MapReduce 編程,因此有了 Hive嗤无。
那 Zookeeper 的作用是什么呢震束?官方文檔上這么解釋?zhuān)核且粋€(gè)分布式服務(wù)框架,是 Apache Hadoop 的一個(gè)子項(xiàng)目当犯,它主要是用來(lái)解決分布式應(yīng)用中經(jīng)常遇到的一些數(shù)據(jù)管理問(wèn)題垢村,如:統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)嚎卫、集群管理嘉栓、分布式應(yīng)用配置項(xiàng)的管理等。
在之前的文章中拓诸,我們搭建了 Hadoop 集群侵佃,里面有一個(gè) Master,多個(gè) Slave Worker奠支,我們需要一個(gè)系統(tǒng)馋辈,來(lái)告訴客戶(hù)端,哪個(gè)是 Master倍谜,哪個(gè)是 Worker迈螟,如果掉線如何處理等。因此 ZooKeeper 隆重登場(chǎng)尔崔。
那它們是如何實(shí)現(xiàn)的呢答毫,我相信這才是大家關(guān)心的東西。
ZooKeeper 在實(shí)現(xiàn)這些服務(wù)時(shí)季春,首先它設(shè)計(jì)一種新的數(shù)據(jù)結(jié)構(gòu)——Znode洗搂,然后在該數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)上定義了一些關(guān)于該結(jié)構(gòu)的操作。有了這些還不夠载弄,因?yàn)?ZooKeeper 是工作在一個(gè)分布式的環(huán)境下耘拇,我們的服務(wù)是通過(guò)消息以網(wǎng)絡(luò)的形式發(fā)送給我們的分布式應(yīng)用程序,所以還需要一個(gè)通知機(jī)制——Watcher 監(jiān)聽(tīng)機(jī)制宇攻。
簡(jiǎn)單來(lái)說(shuō)驼鞭,雖然不準(zhǔn)確,Zookeeper = 文件系統(tǒng) + 監(jiān)聽(tīng)通知機(jī)制尺碰。
二、Zookeeper 安裝與使用
1、在 Apache ZooKeeper 下載并解壓亲桥。
$ tar -xzvf apache-zookeeper-x.y.z-bin.tar.gz
2洛心、復(fù)制 zookeeper 中 conf 文件夾下的 zoo_sample.cfg
文件并命名為 zoo.cfg
。
$ cp zoo_sample.cfg zoo.cfg
3题篷、修改 zoo.cfg
內(nèi)容词身。
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just example sakes.
dataDir=/Users/terry-jri/Downloads/soft_tmp/zookeeper
# the port at which the clients will connect
clientPort=2181
4、配置環(huán)境變量
$ vim /etc/profile
加入 zookeeper 環(huán)境變量
export ZOOKEEPER_HOME=/Users/terry-jri/Downloads/soft/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin
5番枚、啟動(dòng) zk 服務(wù)器
$ zkServer.sh start
6法严、驗(yàn)證 zk 是否啟動(dòng)成功
$ zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /Users/terry-jri/Downloads/soft/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: standalone
7、啟動(dòng)客戶(hù)端連接到服務(wù)器
$ zkCli.sh -server 127.0.0.1:2181
8葫笼、zk 常用命令
[zk] help //查看幫助
[zk] quit //退出
[zk] create /a tom //創(chuàng)建節(jié)點(diǎn)且節(jié)點(diǎn) a 且數(shù)據(jù)為 tom
[zk] get /a //查看數(shù)據(jù)
[zk] ls / //列出節(jié)點(diǎn)
[zk] set /a tom //設(shè)置數(shù)據(jù)
[zk] delete /a //刪除一個(gè)節(jié)點(diǎn)
[zk] rmr /a
三深啤、ZooKeeper 架構(gòu)
從圖中我們可以看出 ZooKeeper 的數(shù)據(jù)模型,在結(jié)構(gòu)上和標(biāo)準(zhǔn)文件系統(tǒng)的非常相似路星,都是采用樹(shù)形層次結(jié)構(gòu)溯街,ZooKeeper 樹(shù)中的每個(gè)節(jié)點(diǎn)被稱(chēng)為 Znode。和文件系統(tǒng)的目錄樹(shù)一樣洋丐,ZooKeeper 樹(shù)中的每個(gè)節(jié)點(diǎn)可以擁有子節(jié)點(diǎn)呈昔。
Znode 兼具文件和目錄兩種特點(diǎn)。既像文件一樣維護(hù)著數(shù)據(jù)友绝、元信息堤尾、ACL、時(shí)間戳等數(shù)據(jù)結(jié)構(gòu)迁客,又像目錄一樣可以作為路徑標(biāo)識(shí)的一部分郭宝。圖中的每個(gè)節(jié)點(diǎn)稱(chēng)為一個(gè) Znode。 每個(gè) Znode 由 3 部分組成:
(1) stat:此為狀態(tài)信息哲泊,描述該 Znode 的版本剩蟀,權(quán)限等信息
(2) data:與該 Znode 關(guān)聯(lián)的數(shù)據(jù)
(3) children:該 Znode 下的子節(jié)點(diǎn)
Znode 雖然可以關(guān)聯(lián)一些數(shù)據(jù),但并沒(méi)有被設(shè)計(jì)為數(shù)據(jù)庫(kù)切威,相反的是育特,它用來(lái)管理調(diào)度數(shù)據(jù),比如先朦,分布式應(yīng)用中的配置文件信息缰冤、狀態(tài)信息、匯集位置等等喳魏。這些數(shù)據(jù)的共同特性就是它們都是很小的數(shù)據(jù)棉浸,通常以 KB 為大小單位。每個(gè) Znode 的數(shù)據(jù)大小至多 1M刺彩,但常規(guī)使用中應(yīng)該遠(yuǎn)小于此值迷郑。
四枝恋、觀察者
客戶(hù)端可以在節(jié)點(diǎn)上設(shè)置 watch,稱(chēng)之為觀察者嗡害。當(dāng)節(jié)點(diǎn)狀態(tài)發(fā)生改變時(shí) (增焚碌、刪、改) 將會(huì)觸發(fā) watch 所對(duì)應(yīng)的操作霸妹。當(dāng) watch 被觸發(fā)時(shí)十电,ZooKeeper 將會(huì)向客戶(hù)端發(fā)送且僅發(fā)送一條通知,因?yàn)?watch 只能被觸發(fā)一次叹螟。
那如何反復(fù)收到通知呢鹃骂?
可以在收到通知時(shí),再注冊(cè)通知罢绽,這樣就可以反復(fù)收到通知畏线。
五、zk 工作流程
zk 集群?jiǎn)?dòng)后有缆,client 連接到其中的一個(gè)節(jié)點(diǎn)象踊,這個(gè)節(jié)點(diǎn)可以是 leader,也可以是 follower棚壁。連通后杯矩,該節(jié)點(diǎn)將分配一個(gè) session ID 給 client,并發(fā)送 ack 信息袖外。如果客戶(hù)端沒(méi)有收到 ack史隆,則會(huì)嘗試連接到另一個(gè)節(jié)點(diǎn)。client 也會(huì)周期性發(fā)送心跳信息給節(jié)點(diǎn)保證連接不會(huì)丟失曼验。
當(dāng) client 讀取 zk 集群數(shù)據(jù)時(shí)泌射,將發(fā)送讀請(qǐng)求給節(jié)點(diǎn),節(jié)點(diǎn)直接讀取自己數(shù)據(jù)庫(kù)鬓照,返回節(jié)點(diǎn)數(shù)據(jù)給 client熔酷。這也是 zk 集群讀取數(shù)據(jù)非常快的原因豺裆。
當(dāng) client 寫(xiě)入數(shù)據(jù)時(shí)拒秘,將 znode 路徑和數(shù)據(jù)發(fā)送給 server,server 轉(zhuǎn)發(fā)給 leader臭猜。leader 再補(bǔ)發(fā)請(qǐng)求給所有 follower躺酒。只有大多數(shù) (超過(guò)半數(shù)) 節(jié)點(diǎn)成功響應(yīng),則寫(xiě)操作成功蔑歌。因此 zk 集群一般由奇數(shù)個(gè)節(jié)點(diǎn)構(gòu)成羹应。
六、Znode
Znode 可分為 3 種次屠,分別是持久節(jié)點(diǎn)园匹、臨時(shí)節(jié)點(diǎn)雳刺、序列節(jié)點(diǎn)。
(1)持久節(jié)點(diǎn) (persistence)
該節(jié)點(diǎn)的生命周期不依賴(lài)于會(huì)話偎肃,并且只有在客戶(hù)端顯示執(zhí)行刪除操作的時(shí)候煞烫,他們才能被刪除。默認(rèn)情況下累颂,創(chuàng)建的就是持久節(jié)點(diǎn)。
(2)臨時(shí)節(jié)點(diǎn) (ephemeral)
臨時(shí)節(jié)點(diǎn)生命周期依賴(lài)于創(chuàng)建它們的會(huì)話凛俱。一旦會(huì)話 (Session) 結(jié)束紊馏,臨時(shí)節(jié)點(diǎn)將被自動(dòng)刪除,當(dāng)然也可以手動(dòng)刪除蒲犬,且臨時(shí)節(jié)點(diǎn)不能有子節(jié)點(diǎn)朱监。
雖然每個(gè)臨時(shí)的Znode都會(huì)綁定到一個(gè)客戶(hù)端會(huì)話,但他們對(duì)所有的客戶(hù)端還是可見(jiàn)的原叮。
leader推選是使用赫编。
(3)序列節(jié)點(diǎn) (sequential)
在節(jié)點(diǎn)名之后附加 10 位數(shù)字,主要用于同步和鎖奋隶。例如創(chuàng)建一個(gè) /myapp
的序列節(jié)點(diǎn)擂送,zk 將會(huì)改變路徑為 /myapp0000000001
七、Leader 推選過(guò)程 (最小號(hào)選舉法)
在分布式服務(wù)中唯欣,有一種典型場(chǎng)景嘹吨,就是通過(guò)集群 Master 選舉,來(lái)解決分布式系統(tǒng)中的單點(diǎn)故障 (SPOF)境氢。
什么是分布式系統(tǒng)中的單點(diǎn)故障:通常分布式系統(tǒng)采用主從模式蟀拷,就是一個(gè)主控機(jī)連接多個(gè)處理節(jié)點(diǎn)。主節(jié)點(diǎn)負(fù)責(zé)分發(fā)任務(wù)萍聊,從節(jié)點(diǎn)負(fù)責(zé)處理任務(wù)问芬,當(dāng)我們的主節(jié)點(diǎn)發(fā)生故障時(shí),那么整個(gè)系統(tǒng)就都癱瘓了寿桨,那么我們把這種故障叫作單點(diǎn)故障此衅。
傳統(tǒng)方式是采用一個(gè)備用節(jié)點(diǎn),這個(gè)備用節(jié)點(diǎn)定期給當(dāng)前主節(jié)點(diǎn)發(fā)送 ping 包牛隅,主節(jié)點(diǎn)收到 ping 包以后向備用節(jié)點(diǎn)發(fā)送回復(fù) ack炕柔,當(dāng)備用節(jié)點(diǎn)收到回復(fù)的時(shí)候就會(huì)認(rèn)為當(dāng)前主節(jié)點(diǎn)還活著,讓他繼續(xù)提供服務(wù)媒佣。
但是這種方式就是有一個(gè)隱患匕累,如果主節(jié)點(diǎn)的并沒(méi)有掛,只是在與備節(jié)點(diǎn)通信時(shí)默伍,網(wǎng)絡(luò)發(fā)生故障欢嘿,這樣備用節(jié)點(diǎn)同樣收不到回復(fù)衰琐,就會(huì)認(rèn)為主節(jié)點(diǎn)掛了,然后備用節(jié)點(diǎn)將他的 Master 實(shí)例啟動(dòng)起來(lái)炼蹦,這樣我們的分布式系統(tǒng)當(dāng)中就有了兩個(gè)主節(jié)點(diǎn)羡宙,也就是雙 Master。
Master 以后我們的從節(jié)點(diǎn)就會(huì)將它所做的事一部分匯報(bào)給了主節(jié)點(diǎn)掐隐,一部分匯報(bào)給了備節(jié)點(diǎn)狗热,這樣服務(wù)就全亂了。
那么 zk 是如何解決這個(gè)問(wèn)題的呢虑省?
所有節(jié)點(diǎn)將在同一目錄下創(chuàng)建臨時(shí)序列節(jié)點(diǎn)匿刮,則節(jié)點(diǎn)下會(huì)生成 /xxx/xx000000001、/xxx/xx000000002 等節(jié)點(diǎn)探颈。序號(hào)最小的節(jié)點(diǎn)就是leader熟丸,其余就是follower.
每個(gè)節(jié)點(diǎn)觀察小于自己節(jié)點(diǎn)的主機(jī)。(注冊(cè)觀察者)
如果 leader 掛了伪节,對(duì)應(yīng) znode 刪除了光羞,觀察者將會(huì)收到通知,然后再次發(fā)出選舉怀大,這時(shí)候第二小的節(jié)點(diǎn)將成為 leader纱兑。
如果主節(jié)點(diǎn)恢復(fù)了,他會(huì)再次向 ZooKeeper 注冊(cè)一個(gè)節(jié)點(diǎn)叉寂,這時(shí)候他注冊(cè)的節(jié)點(diǎn)將會(huì)是 /xxx/xx000000003萍启,直到前面的主機(jī)都掛掉,該節(jié)點(diǎn)將再次成為 leader屏鳍。