一篇帶給你Zookeeper教程:入門篇
前言
在分布式系統(tǒng)中,注冊中心充當(dāng)著重要角色,是服務(wù)發(fā)現(xiàn)、客戶端負(fù)載均衡中不可缺少的一員。注冊中心除了能夠?qū)崿F(xiàn)基本的功能外,它的穩(wěn)定性、可用性和健壯性對整個(gè)分布式系統(tǒng)的流暢運(yùn)行影響重大。dubbo作為國內(nèi)一款主流的分布式系統(tǒng),支持的注冊中心有zookeeper、nacos和redis等第三方中間件。
高并發(fā)分布式開發(fā)技術(shù)體系已然非常的龐大,前段時(shí)間一直在準(zhǔn)備找工作,參加面試,通過面試的情況可以發(fā)現(xiàn)RPC、Dubbo、zookeeper、nacos、分布式、微服務(wù)等這些已經(jīng)成為了找工作的最基礎(chǔ)的技能要求了。
之前有篇文章介紹到了如何使用nacos作為注冊中心:SpringCloud:搭建Nacos服務(wù)以及服務(wù)發(fā)現(xiàn)。其實(shí)不僅僅nacos可以作為注冊中心,zookeeper也可以作為注冊中心使用。但是Zookeeper其實(shí)不僅僅可以作為注冊中心。
對于Zookeeper,其官方文檔上的解釋是:它是一個(gè)分布式服務(wù)框架,是Apache Hadoop 的一個(gè)子項(xiàng)目,它主要是用來解決分布式應(yīng)用中經(jīng)常遇到的一些數(shù)據(jù)管理問題,如:統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式應(yīng)用配置項(xiàng)的管理等??梢岳斫鉃閦ookeeper是文件系統(tǒng)+監(jiān)聽通知機(jī)制。
今天這篇文章就一起來學(xué)習(xí)學(xué)習(xí)Zookeeper,我自己也是學(xué)習(xí)的過程!
什么是zookeeper
隨著系統(tǒng)應(yīng)用的拓展和數(shù)據(jù)量的保證,我們的系統(tǒng)經(jīng)常會遇到這些情況:
- 怎么保證一個(gè)服務(wù)器集群中的所有服務(wù)器保持共享的配置信息的一致性?
- 如果服務(wù)器集群中有一臺機(jī)器掛掉了,其他機(jī)器如何感知到這一變化并接管任務(wù)?
- 對于分布式系統(tǒng),如何高效協(xié)同多臺服務(wù)對同一網(wǎng)絡(luò)文件進(jìn)行寫操作并保持一致性?
- 如何做到不重啟集群而完成機(jī)器的添加?
- ........
為了解決上述的問題,就需要一個(gè)類似于線程協(xié)同機(jī)制的工具,讓各個(gè)服務(wù)進(jìn)行協(xié)同工作。而zookeeper就是這樣的一類工具。
上面說到對于Zookeeper,其官方文檔上的解釋是:它是一個(gè)分布式服務(wù)框架,是Apache Hadoop 的一個(gè)子項(xiàng)目,它主要是用來解決分布式應(yīng)用中經(jīng)常遇到的一些數(shù)據(jù)管理問題,如:統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式應(yīng)用配置項(xiàng)的管理等。
所以可以理解為zookeeper是一種可以用于分布式應(yīng)用的高性能協(xié)調(diào)服務(wù),它的數(shù)據(jù)是存于內(nèi)存中的,并且持久化實(shí)現(xiàn)在日志中。而它的內(nèi)存結(jié)構(gòu)是類似于樹形結(jié)構(gòu),具有高吞吐低延遲的特點(diǎn)。zookeeper不僅僅可以幫助我們實(shí)現(xiàn)分布式統(tǒng)一配置中心,服務(wù)注冊,分布式鎖等,它們維護(hù)內(nèi)存中的狀態(tài)圖像,以及持久性存儲中的事務(wù)日志和快照。只要大多數(shù)服務(wù)器可用,ZooKeeper服務(wù)就可用??蛻舳诉B接到單個(gè)ZooKeeper服務(wù)器。客戶端維護(hù)TCP連接,通過該連接發(fā)送請求,獲取響應(yīng),獲取監(jiān)視事件以及發(fā)送tick。如果與服務(wù)器的TCP連接中斷,則客戶端將連接到其他服務(wù)器。所以可以簡單地認(rèn)為zookeeper=文件系統(tǒng)+監(jiān)聽通知機(jī)制。
我們還可以這樣理解:zookeeper的中文意思就是動(dòng)物園管理員(zoom+keeper)。動(dòng)物園管理員的作用就是負(fù)責(zé)管理動(dòng)物園里面的動(dòng)物,讓它們井然有序。而zookeeper是apache下的開源項(xiàng)目,在apache下的很多開源項(xiàng)目其實(shí)都是以動(dòng)物作為圖標(biāo)的,比如Hadoop(大象),Hive(蜜蜂),Pig(小豬)、tomcat(貓)。
所以可以記憶成apache下的項(xiàng)目就是動(dòng)物園,而zookeeper就是負(fù)責(zé)管理這些動(dòng)物(開源項(xiàng)目)的動(dòng)物管理員。
zookeeper的數(shù)據(jù)結(jié)構(gòu)
zookeeper 會維護(hù)一個(gè)具有層次關(guān)系的數(shù)據(jù)結(jié)構(gòu),它非常類似于一個(gè)標(biāo)準(zhǔn)的文件系統(tǒng):
上圖中的樹形結(jié)構(gòu)中的每個(gè)節(jié)點(diǎn)(目錄項(xiàng)),比如NameService 都被稱作為 znode(目錄節(jié)點(diǎn))。zonde通過路徑引用,路徑必須是絕對的,因此他們必須由斜杠字符來開頭。除此以外,它們必須是唯一的,也就是說每一個(gè)路徑只有一個(gè)表示,因此這些路徑不能改變。在zookeeper中,路徑由Unicode字符串組成,并且有一些限制。字符串"/ZooKeeper"用以保存管理信息,比如關(guān)鍵配額信息。
znode同時(shí)具有文件和目錄兩種特點(diǎn)。既像文件一樣維護(hù)著數(shù)據(jù)、元信息、訪問控制列表)、時(shí)間戳等數(shù)據(jù)結(jié)構(gòu),又可以像目錄一樣可以作為路徑標(biāo)識的一部分,能夠自由的增加、刪除znode。
每個(gè)znode都是由三部分組成:
- stat:此為狀態(tài)信息, 描述該znode的版本, 權(quán)限等信息
- data:與該znode關(guān)聯(lián)的數(shù)據(jù)
- children:該znode下的子節(jié)點(diǎn)
需要注意的是同一個(gè)節(jié)點(diǎn)下的子節(jié)點(diǎn)名稱不能相同,且命名是有規(guī)范的,它的路徑是沒有相對路徑的概念的,都是絕對路徑,任何開始都以"/"開始,最后就是,它存放數(shù)據(jù)的大小是有限制的。
zookeeper的節(jié)點(diǎn)類型
zookeeper中的節(jié)點(diǎn)有兩種,分別為臨時(shí)節(jié)點(diǎn)(Ephemeral Node)和永久節(jié)點(diǎn)(Persistent Node)。節(jié)點(diǎn)的類型在創(chuàng)建時(shí)即被確定,并且不能改變。
兩種節(jié)點(diǎn)的區(qū)別在于是否依賴于會話(Session)而生存。客戶端和ZooKeeper服務(wù)器的一次連接稱為一次會話??蛻舳丝颗c服務(wù)器建立一個(gè)TCP的長連接來維持一個(gè)會話,客戶端在啟動(dòng)的時(shí)候首先會與服務(wù)器建立一個(gè)TCP連接,通過這個(gè)連接客戶端能夠通過心跳檢測與服務(wù)器保持有效的會話,也能向ZooKeeper服務(wù)器發(fā)送請求并獲得響應(yīng)。
(1)臨時(shí)節(jié)點(diǎn):該節(jié)點(diǎn)的生命周期依賴于創(chuàng)建它們的會話。一旦會話結(jié)束,臨時(shí)節(jié)點(diǎn)將被自動(dòng)刪除,當(dāng)然也可以手動(dòng)刪除。雖然每個(gè)臨時(shí)的Znode都會綁定到一個(gè)客戶端會話,但他們對所有的客戶端還是可見的。另外,zookeeper的臨時(shí)節(jié)點(diǎn)不允許擁有子節(jié)點(diǎn)。臨時(shí)節(jié)點(diǎn)又可以細(xì)分為:臨時(shí)目錄節(jié)點(diǎn)和臨時(shí)順序編號目錄節(jié)點(diǎn)。
- 臨時(shí)目錄節(jié)點(diǎn)(EPHEMERAL):客戶端與zookeeper斷開連接后,該節(jié)點(diǎn)被刪除。
- 臨時(shí)順序編號目錄節(jié)點(diǎn)(EPHEMERAL_SEQUENTIAL):客戶端與zookeeper斷開連接后,該節(jié)點(diǎn)被刪除,只是Zookeeper給該節(jié)點(diǎn)名稱進(jìn)行順序編號。
(2)永久節(jié)點(diǎn):該節(jié)點(diǎn)的生命周期不依賴于會話,并且只有在客戶端執(zhí)行刪除操作的時(shí)候,他們才能被刪除。臨時(shí)節(jié)點(diǎn)又可以細(xì)分為:持久目錄節(jié)點(diǎn)和持久順序編號目錄節(jié)點(diǎn)。
- 持久化目錄節(jié)點(diǎn)(PERSISTENT):客戶端與zookeeper斷開連接后,該節(jié)點(diǎn)依舊存在。
- 持久化順序編號目錄節(jié)點(diǎn)(PERSISTENT_SEQUENTIAL):客戶端與zookeeper斷開連接后,該節(jié)點(diǎn)依舊存在,只是zookeeper給該節(jié)點(diǎn)名稱進(jìn)行順序編號。
上面的分類有個(gè)概念叫順序節(jié)點(diǎn):在創(chuàng)建節(jié)點(diǎn)的時(shí)候,用戶可以請求在zooKeeper的路徑結(jié)尾添加一個(gè)遞增的計(jì)數(shù)。這個(gè)計(jì)數(shù)對于此節(jié)點(diǎn)的父節(jié)點(diǎn)來說是唯一的,當(dāng)客戶端請求創(chuàng)建這個(gè)節(jié)點(diǎn)后,zookeeper會根據(jù)父節(jié)點(diǎn)的zxid狀態(tài),為這個(gè)節(jié)點(diǎn)編寫一個(gè)全目錄唯一的編號,并且這個(gè)編號只會一直增長。這樣的節(jié)點(diǎn)稱為順序節(jié)點(diǎn)。
這上面又提到了一個(gè)概念叫zxid:對于改變zookeeper節(jié)點(diǎn)狀態(tài)的每一個(gè)操作都將使這個(gè)節(jié)點(diǎn)接收到一個(gè)Zxid格式的時(shí)間戳,并且這個(gè)時(shí)間戳全局有序??梢岳斫鉃槊總€(gè)改變對節(jié)點(diǎn)的操作都會產(chǎn)生一個(gè)唯一的事務(wù)id叫做Zxid。如果Zxid1的值小于Zxid2的值,那么就可以認(rèn)為Zxid1所對應(yīng)的事件發(fā)生在Zxid2所對應(yīng)的事件之前。其實(shí),zookeeper的每個(gè)節(jié)點(diǎn)都維護(hù)著兩個(gè)Zxid值,分別是:cZxid、mZxid。
- cZxid:指的是節(jié)點(diǎn)的創(chuàng)建時(shí)間所對應(yīng)的Zxid格式時(shí)間戳。
- mZxid:指的是節(jié)點(diǎn)的修改時(shí)間所對應(yīng)的Zxid格式時(shí)間戳。
實(shí)現(xiàn)中Zxid是一個(gè)64位的數(shù)字,它高32位是epoch(投票)用來標(biāo)識Leader關(guān)系是否改變,每次一個(gè)Leader被選出來,它都會有一個(gè)新的epoch。而第32位就是個(gè)遞增計(jì)數(shù)。
zookeeper的特點(diǎn)
1、有序性
zookeeper提供了多種方式跟蹤時(shí)間,zookeeper給每個(gè)更新貼上一個(gè)數(shù)字(前面說的zxid),這個(gè)數(shù)字反映了所有zookeeper事務(wù)的順序,嚴(yán)格的順序意味著可以在客戶機(jī)上實(shí)現(xiàn)復(fù)雜的同步。除了上面說到的zxid,還有version、zoo.cfg中ticks配置。
version numbers(版本號):版本號是用來記錄節(jié)點(diǎn)數(shù)據(jù)或者是節(jié)點(diǎn)的子節(jié)點(diǎn)列表或者是權(quán)限信息的修改次數(shù)。如果一個(gè)節(jié)點(diǎn)的version是1,那就代表說這個(gè)節(jié)點(diǎn)從創(chuàng)建以來被修改了一次。
每個(gè)節(jié)點(diǎn)維護(hù)著三個(gè)版本號,他們分別為:
- version:節(jié)點(diǎn)數(shù)據(jù)版本號。
- cversion:子節(jié)點(diǎn)版本號。
- aversion:節(jié)點(diǎn)所擁有的ACL版本號。
對節(jié)點(diǎn)的寫請求都會導(dǎo)致該節(jié)點(diǎn)的3種版本號增加,原理和樂觀鎖差不多。
ticks :zoo.cfg文件中的配置。當(dāng)使用多服務(wù)器zookeeper時(shí),服務(wù)器使用一個(gè)“滴答”來定義事件的時(shí)間,如狀態(tài)上傳,會話超時(shí)等,它通過最小會話超時(shí)(默認(rèn)是滴答時(shí)間x2)間接公開,如果客戶端請求超過這個(gè)時(shí)間,那客戶端就不再能連接上服務(wù)器端。
real time:zookeeper并不使用真實(shí)時(shí)間。
所以可以理解為zookeeper是一個(gè)協(xié)調(diào)者,使得一些交互連接有序進(jìn)行!
速度快。
前面提到了zookeeper的數(shù)據(jù)加載在內(nèi)存中,所以它具有高吞吐和低延遲的效果。并且以讀取為事務(wù)速度尤其快,而且操作的znode大小限制在1m。正是這些特點(diǎn),使得zookeeper可以適用于大型的分布式系統(tǒng)。
2、可復(fù)制
zookeeper的數(shù)據(jù)是可復(fù)制,可備份的。zookeeper可以快速地搭建一個(gè)集群,內(nèi)部自帶了這樣的一些工具與機(jī)制,我們只需要設(shè)置一些配置即可,保證服務(wù)可靠,所以不會成為單點(diǎn)故障。如下:
watcher機(jī)制
zookeeper允許用戶在指定節(jié)點(diǎn)上注冊一些Watcher,當(dāng)數(shù)據(jù)節(jié)點(diǎn)發(fā)生變化的時(shí)候,zookeeper服務(wù)器會把這個(gè)變化的通知發(fā)送給感興趣的客戶端。這個(gè)是zookeeper的核心特性,zookeeper的很多功能都是基于這個(gè)特性實(shí)現(xiàn)的。
如果有兩個(gè)客戶端都在zookeeper集群中注冊了watcher(事件監(jiān)聽器),那么當(dāng)zookeeper中的節(jié)點(diǎn)數(shù)據(jù)發(fā)生變化的時(shí)候,zookeeper會把這一變化的通知發(fā)送給客戶端,當(dāng)客戶端收到這個(gè)變化通知的時(shí)候,會觸發(fā)某些提前定義好的動(dòng)作。一般來說,zookeeper會向客戶端發(fā)送且僅發(fā)送一條通知,如果一個(gè)watch同時(shí)注冊了多個(gè)接口(exists,getData),如果此時(shí)刪除節(jié)點(diǎn),雖然這個(gè)事件對exists和getData都有效,但是watch只會被調(diào)用一次。并且這些請求有可能存在延時(shí),所以不能絕對可靠得到每個(gè)節(jié)點(diǎn)發(fā)生的每個(gè)更改。watch觸發(fā)后會立即刪除,要持續(xù)監(jiān)聽變化的話就需要持續(xù)提供設(shè)置watch。并且客戶端先得到watch通知才可查看變化結(jié)果。
觸發(fā)watch事件的條件有4種,create,delete,change,child(子節(jié)點(diǎn)事件)。
所以可以總結(jié)zookeeper的特點(diǎn)如下:
1、原子性(Atomicity),更新成功或失敗。沒有部分結(jié)果。
2、可靠性:數(shù)據(jù)的變更不會丟失,除非被客戶端覆蓋修改。
3、實(shí)時(shí)性:系統(tǒng)的客戶端當(dāng)時(shí)讀取到的數(shù)據(jù)是最新的。
4、有序性:客戶端的操作都是按照順序生效的。
5、一致性:又叫單個(gè)系統(tǒng)映像,無論連接的是哪個(gè)服務(wù)器,客戶端看到的內(nèi)容都是相同的。
總結(jié)
上述就是關(guān)于zookeeper的簡單介紹。自己也是一個(gè)學(xué)習(xí)的過程??偨Y(jié)了一些關(guān)于zookeeper的概念和相關(guān)知識點(diǎn)。