ZooKeeper 簡(jiǎn)介

分布式應(yīng)用程序的分布式協(xié)調(diào)服務(wù)

ZooKeeper是一個(gè)分布式、開(kāi)源的分布式應(yīng)用程序協(xié)調(diào)服務(wù)。它公開(kāi)了一組簡(jiǎn)單的原語(yǔ),分布式應(yīng)用程序可以在這些原語(yǔ)的基礎(chǔ)上實(shí)現(xiàn)更高級(jí)別的服務(wù),用于同步、配置維護(hù)、組和命名。它被設(shè)計(jì)為易于編程,并使用了一個(gè)數(shù)據(jù)模型,其風(fēng)格類似于文件系統(tǒng)的目錄樹(shù)結(jié)構(gòu)。它運(yùn)行在Java中,并具有Java和C的綁定。
眾所周知,協(xié)調(diào)服務(wù)很難做好。它們特別容易出現(xiàn)競(jìng)爭(zhēng)條件和死鎖等錯(cuò)誤。

ZooKeeper的初心就是減輕分布式應(yīng)用程序從零開(kāi)始實(shí)現(xiàn)協(xié)調(diào)服務(wù)的責(zé)任。

設(shè)計(jì)目標(biāo)

簡(jiǎn)潔

ZooKeeper允許分布式進(jìn)程通過(guò)與標(biāo)準(zhǔn)文件系統(tǒng)組織類似的共享層次命名空間相互協(xié)調(diào)。名稱空間由數(shù)據(jù)寄存器(用ZooKeeper的話說(shuō),稱為znodes)組成,這些寄存器類似于文件和目錄。

與設(shè)計(jì)用于存儲(chǔ)的典型文件系統(tǒng)不同,ZooKeeper數(shù)據(jù)保存在內(nèi)存中,這意味著ZooKeeper可以實(shí)現(xiàn)高吞吐和低延遲。

ZooKeeper實(shí)現(xiàn)非常重視高性能、高可用性和嚴(yán)格有序的訪問(wèn)。

  • ZooKeeper的性能方面意味著它可以用于大型分布式系統(tǒng)。
  • 可靠性方面使其不會(huì)成為單點(diǎn)故障。
  • 嚴(yán)格的順序意味著可以在客戶機(jī)上實(shí)現(xiàn)復(fù)雜的同步原語(yǔ)。

復(fù)制

和它所協(xié)調(diào)的分布式進(jìn)程一樣,ZooKeeper本身也打算在一組稱為合集的主機(jī)上進(jìn)行復(fù)制。組成ZooKeeper服務(wù)的服務(wù)器必須相互了解。它們?cè)诔志么鎯?chǔ)中維護(hù)狀態(tài)的內(nèi)存映像以及事務(wù)日志和快照。只要大多數(shù)服務(wù)器可用,ZooKeeper服務(wù)就可用。
客戶機(jī)連接到單個(gè)ZooKeeper服務(wù)器??蛻魴C(jī)維護(hù)一個(gè)TCP連接,通過(guò)它發(fā)送請(qǐng)求、獲取響應(yīng)、獲取監(jiān)視事件和發(fā)送心跳。如果到服務(wù)器的TCP連接中斷,客戶機(jī)將連接到另一臺(tái)服務(wù)器。

有序的

ZooKeeper給每個(gè)更新貼上一個(gè)數(shù)字,這個(gè)數(shù)字反映了所有ZooKeeper事務(wù)的順序。后續(xù)操作可以使用該順序?qū)崿F(xiàn)更高級(jí)別的抽象,比如同步原語(yǔ)。

高速的

在“以讀取為主”的工作負(fù)載中,它尤其快。ZooKeeper應(yīng)用程序運(yùn)行在數(shù)千臺(tái)機(jī)器上,當(dāng)讀操作比寫操作更常見(jiàn)時(shí),它的性能最好,比率約為10:1。

數(shù)據(jù)模型和層次命名空間

ZooKeeper提供的名稱空間很像標(biāo)準(zhǔn)文件系統(tǒng)。名稱是由斜杠(/)分隔的路徑元素序列。ZooKeeper名稱空間中的每個(gè)節(jié)點(diǎn)都由一條路徑標(biāo)識(shí)。

節(jié)點(diǎn)和短暫節(jié)點(diǎn)

不同于標(biāo)準(zhǔn)文件系統(tǒng),在ZooKeeper的命名空間的每個(gè)節(jié)點(diǎn)都可以具有數(shù)據(jù)跟孩子節(jié)點(diǎn)一樣。 (ZooKeeper是用來(lái)存儲(chǔ)協(xié)調(diào)數(shù)據(jù)的:狀態(tài)信息,配置,位置信息等,所以每個(gè)節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)都很小,在幾個(gè)字節(jié)到千級(jí)別字節(jié)范圍),我們使用術(shù)語(yǔ)Znode,使之清楚,我們 正在談?wù)摰腪ooKeeper數(shù)據(jù)節(jié)點(diǎn)。

Znodes有一個(gè)stat結(jié)構(gòu),包含對(duì)數(shù)據(jù)的變更的版本號(hào),ACL的變化,和時(shí)間戳,允許緩存驗(yàn)證和協(xié)調(diào)的更新。 每當(dāng)Znode的數(shù)據(jù)發(fā)生變更,其版本號(hào)也會(huì)增加。例如,當(dāng)客戶端檢索數(shù)據(jù)時(shí)也會(huì)檢索數(shù)據(jù)的版本號(hào)。

存儲(chǔ)在一個(gè)命名空間中的每個(gè)Znode的數(shù)據(jù)讀取和寫入都是原子的。讀取獲取與Znode節(jié)點(diǎn)相關(guān)聯(lián)的所有數(shù)據(jù)字節(jié)和寫入替換所有的數(shù)據(jù)。每個(gè)節(jié)點(diǎn)都有限制誰(shuí)可以做什么的訪問(wèn)控制列表(ACL)。

ZooKeeper的也有短暫的節(jié)點(diǎn)的概念。這些znodes存在,只要?jiǎng)?chuàng)建的Znode的會(huì)話處于活動(dòng)狀態(tài)。 當(dāng)會(huì)話結(jié)束時(shí),Znode被刪除。 當(dāng)你想實(shí)現(xiàn)[TBD]短暫的節(jié)點(diǎn)是有用的。

條件更新和監(jiān)控

Zookeeper支持監(jiān)控功能,客戶端可以在節(jié)點(diǎn)上設(shè)置一個(gè)監(jiān)控,當(dāng)節(jié)點(diǎn)變更的時(shí)候,監(jiān)控可以被觸發(fā)和移除。當(dāng)一個(gè)監(jiān)控被觸發(fā),客戶端接受到一個(gè)數(shù)據(jù)包,標(biāo)識(shí)znode節(jié)點(diǎn)發(fā)生了變更。如果客戶端和服務(wù)端的鏈接斷開(kāi)了,客戶端將收到一個(gè)本地通知.

保證

Zookeeper非??旌秃?jiǎn)潔,但是,由于它的目標(biāo)是作為構(gòu)建更復(fù)雜服務(wù)(比如同步)的基礎(chǔ),所以它提供了一組保證。如下:

  • 順序一致性——來(lái)自客戶機(jī)的更新將按發(fā)送順序應(yīng)用。
  • 原子性——更新成功或失敗。沒(méi)有部分結(jié)果。
  • 單個(gè)系統(tǒng)映像——無(wú)論服務(wù)連接到哪個(gè)服務(wù)器,客戶機(jī)都將看到相同的服務(wù)視圖。
  • 可靠性——一旦應(yīng)用了更新,它將從那時(shí)起一直持續(xù)到客戶機(jī)覆蓋更新為止。
  • 及時(shí)性——保證系統(tǒng)的客戶端視圖在一定的時(shí)間范圍內(nèi)是最新的。

相關(guān)接口

ZooKeeper的設(shè)計(jì)目標(biāo)之一是提供一個(gè)非常簡(jiǎn)單的編程接口。因此,它只支持這些操作

  • create:樹(shù)中的一個(gè)位置創(chuàng)建一個(gè)節(jié)點(diǎn)
  • delete:刪除一個(gè)節(jié)點(diǎn)
  • exists:測(cè)試一個(gè)位置上的節(jié)點(diǎn)是否存在
  • get data:從節(jié)點(diǎn)上讀取數(shù)據(jù)
  • set data:寫數(shù)據(jù)到節(jié)點(diǎn)上
  • get children:檢索節(jié)點(diǎn)上的子節(jié)點(diǎn)
  • sync:等待要傳播的數(shù)據(jù)

實(shí)現(xiàn)

除了請(qǐng)求處理器之外,除請(qǐng)求處理器外,構(gòu)成ZooKeeper服務(wù)的每個(gè)服務(wù)器都復(fù)制其自己的每個(gè)組件副本。

復(fù)制數(shù)據(jù)庫(kù)是包含整個(gè)數(shù)據(jù)樹(shù)中的內(nèi)存數(shù)據(jù)庫(kù)。將更新記錄到磁盤以確??苫謴?fù)性,并且將寫入操作序列化到磁盤之后再將其應(yīng)用于內(nèi)存數(shù)據(jù)庫(kù)。

每個(gè)ZooKeeper服務(wù)器都為客戶端提供服務(wù)。 客戶端連接到確定的某一個(gè)服務(wù)器提交請(qǐng)求。 讀取請(qǐng)求從每個(gè)服務(wù)器數(shù)據(jù)庫(kù)的本地副本提供服務(wù)。 改變服務(wù)的狀態(tài)、寫請(qǐng)求的請(qǐng)求,由一個(gè)一致性協(xié)議處理。

作為一致性協(xié)議的一部分,所有來(lái)自客戶端的寫請(qǐng)求都被轉(zhuǎn)發(fā)到一個(gè)名為leader的服務(wù)器上。其他的ZooKeeper服務(wù)器(稱為followers)接收來(lái)自leader的消息建議,并就消息傳遞達(dá)成一致。消息層負(fù)責(zé)在失敗時(shí)替換leader,并將followers與leader同步。

ZooKeeper使用自定義原子消息傳遞協(xié)議。因?yàn)橄邮窃拥?,所以ZooKeeper可以保證本地副本不會(huì)偏離。當(dāng)leader接收到寫請(qǐng)求時(shí),它會(huì)計(jì)算要應(yīng)用寫時(shí)系統(tǒng)的狀態(tài),并將其轉(zhuǎn)換為捕獲這個(gè)新?tīng)顟B(tài)的事務(wù)。

單機(jī)模式

安裝單機(jī)模式的Zookeeper很簡(jiǎn)單,服務(wù)器包含著單個(gè)jar文件中,所以,安裝包內(nèi)包含創(chuàng)建一個(gè)配置文件,一旦下載下了Zookeeper,解壓他,并cd到根目錄下.為了啟動(dòng)Zookeeper,需要?jiǎng)?chuàng)建一個(gè)配置文件,下面的示例很簡(jiǎn)單,創(chuàng)建一個(gè)conf/zoo.cfg,內(nèi)容如下:

tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181

根據(jù)實(shí)際情況,dataDir修改成存在的目錄,下面介紹一下幾個(gè)配置項(xiàng)的含義:

  • tickTime:基礎(chǔ)時(shí)間單元,單位為微秒,用于心跳和最小session超時(shí)時(shí)長(zhǎng)的2倍
  • dataDir:內(nèi)存數(shù)據(jù)庫(kù)快照的存儲(chǔ)位置,除非另有說(shuō)明,否則事務(wù)日志將更新到數(shù)據(jù)庫(kù)
  • clientPort:客戶端連接的監(jiān)聽(tīng)端口

創(chuàng)建配置文件完成后,即可開(kāi)啟Zookeeper
bin/zkServer.sh start

Zookeeper日志系統(tǒng)使用的是log4j.你可以通過(guò)log4j配置來(lái)使日志輸出到控制臺(tái)打印或者日志文件中。
到目前位置,Zookeeper都是運(yùn)行在單機(jī)模式下。沒(méi)有副本,如果Zookeeper進(jìn)程掛了,整個(gè)服務(wù)將暫定, 僅適用于開(kāi)發(fā)者環(huán)境

管理Zookeeper存儲(chǔ)

對(duì)于生產(chǎn)環(huán)境下,Zookeeper長(zhǎng)時(shí)間運(yùn)行。數(shù)據(jù)存儲(chǔ)需要明確管理。

連接Zookeeper

bin/zkCli.sh -server 127.0.0.1:2181

就像是文件操作一樣,一但你成功連接,可以看到如下信息:

Connecting to localhost:2181
log4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper).
log4j:WARN Please initialize the log4j system properly.
Welcome to ZooKeeper!
JLine support is enabled
[zkshell: 0]

通過(guò)Shell,鍵入help,可以獲得客戶端可以執(zhí)行的命令列表。如下:

[zkshell: 0] help
ZooKeeper host:port cmd args
    get path [watch]
    ls path [watch]
    set path data [version]
    delquota [-n|-b] path
    quit
    printwatches on|off
    create path data acl
    stat path [watch]
    listquota path
    history
    setAcl path acl
    getAcl path
    sync path
    redo cmdno
    addauth scheme auth
    delete path [version]
    deleteall path
    setquota -n|-b val path

到這里,你可以嘗試輸入一個(gè)簡(jiǎn)單的命令,ls

[zkshell: 8] ls /
[zookeeper]

接下來(lái),通過(guò)create /zk_test mydata創(chuàng)建一個(gè)新的znode,這將創(chuàng)建一個(gè)新的znode并關(guān)聯(lián)了字符串"my_data".可以看到:

[zkshell: 9] create /zk_test my_data
Created /zk_test

再次鍵入:

[zkshell: 11] ls /
[zookeeper, zk_test]

表明zk_test目錄已經(jīng)創(chuàng)建成功。
接下來(lái),驗(yàn)證數(shù)據(jù)關(guān)聯(lián)節(jié)點(diǎn),通過(guò)get命名:

[zkshell: 12] get /zk_test
my_data
cZxid = 5
ctime = Fri Jun 05 13:57:06 PDT 2009
mZxid = 5
mtime = Fri Jun 05 13:57:06 PDT 2009
pZxid = 5
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0
dataLength = 7
numChildren = 0

我們可以變更zk_test關(guān)聯(lián)的數(shù)據(jù),通過(guò)set命令:

[zkshell: 14] set /zk_test junk
cZxid = 5
ctime = Fri Jun 05 13:57:06 PDT 2009
mZxid = 6
mtime = Fri Jun 05 14:01:52 PDT 2009
pZxid = 5
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0
dataLength = 4
numChildren = 0
[zkshell: 15] get /zk_test
junk
cZxid = 5
ctime = Fri Jun 05 13:57:06 PDT 2009
mZxid = 6
mtime = Fri Jun 05 14:01:52 PDT 2009
pZxid = 5
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0
dataLength = 4
numChildren = 0

最后,可以通過(guò)delete命令刪除節(jié)點(diǎn):

[zkshell: 16] delete /zk_test
[zkshell: 17] ls /
[zookeeper]
[zkshell: 18]

副本模式Zookeeper

單機(jī)模式的Zookeeper僅用于開(kāi)發(fā)測(cè)試,生產(chǎn)環(huán)境下,你需要使用副本模式,同一應(yīng)用程序中的復(fù)制服務(wù)器組稱為quorum,并處于復(fù)制模式,quorum中的所有服務(wù)器都具有相同配置文件的副本。


注:在副本模式中,最小數(shù)目的服務(wù)器數(shù)量為3個(gè),強(qiáng)烈建議,需要一個(gè)奇數(shù)數(shù)目的服務(wù)器,如果你只有兩個(gè)服務(wù)器,那么當(dāng)一個(gè)掛機(jī)后,沒(méi)有足夠數(shù)量的機(jī)器來(lái)仲裁選舉,兩臺(tái)服務(wù)器本質(zhì)上比一臺(tái)服務(wù)器更不穩(wěn)定,因?yàn)橛袃蓚€(gè)單點(diǎn)故障。


這種模式下的配置文件,與單機(jī)模式下的配置文件,大同小異:

tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888

新的配置項(xiàng):

  • initLimit: 集群中的follower服務(wù)器(F)與leader服務(wù)器(L)之間 初始連接 時(shí)能容忍的最多心跳數(shù)(tickTime的數(shù)量)。

此配置表示,允許 follower (相對(duì)于 leader 而言的“客戶端”)連接 并同步到 leader 的初始化連接時(shí)間,它以 tickTime 的倍數(shù)來(lái)表示。當(dāng)超過(guò)設(shè)置倍數(shù)的 tickTime 時(shí)間,則連接失敗。

  • syncLimit: 標(biāo)識(shí)參數(shù)設(shè)定了允許一個(gè)跟隨者與一個(gè)領(lǐng)導(dǎo)者進(jìn)行同步的時(shí)間,如果在設(shè)定的時(shí)間段內(nèi),跟隨者未完成同步,它將會(huì)被集群丟棄。所有關(guān)聯(lián)到這個(gè)跟隨者的客戶端將連接到另外一個(gè)跟隨著。

server.X列表列出了組成Zookeeper服務(wù)的服務(wù)器列表。當(dāng)服務(wù)啟動(dòng)后,通過(guò)文件的myid查找哪個(gè)服務(wù)器。這個(gè)文件包含ASCII形式的服務(wù)編碼。

最后,每個(gè)服務(wù)器名后面,有兩個(gè)端口,這個(gè)是兩個(gè)端用于連接通信的端口。

Zookeeper數(shù)據(jù)模型

Zookeeper有一個(gè)命名空間模型,就像是分布式的文件系統(tǒng)一樣。唯一的不同是,命名空間中的每一個(gè)節(jié)點(diǎn)都可以有與之關(guān)聯(lián)的數(shù)據(jù),和子節(jié)點(diǎn)一樣。就像是文件系統(tǒng)中允許一個(gè)文件可以是一個(gè)目錄一樣。節(jié)點(diǎn)的路徑總是表示為規(guī)范的、絕對(duì)的、斜杠分隔的路徑。沒(méi)有相對(duì)路徑。
任何unicode字符都可以在受以下約束的路徑中使用:

  • null字符(\u0000)不能作為路徑的一部分。
  • 以下字符不能用,因?yàn)樗麄儾荒鼙缓芎玫恼故?,或則以一種疑惑的方式:(\u0001-\u001F)和\u007F-\u009F
  • 下面的字符也不被允許\ud800-\uF8FF,\uFFF0-\uFFFF
  • .字符可以被用于名稱的一部分,但是...不能單獨(dú)用于在路徑中表明一個(gè)節(jié)點(diǎn)。因?yàn)閆ookeeper不能使用相對(duì)路徑。所以下面的路徑是非法的/a/b/./c/a/b/../c
  • zookeeper是保留字

ZNodes

在Zookeeper樹(shù)中,每個(gè)節(jié)點(diǎn)作為一個(gè)znode。Znode維護(hù)一個(gè)包含數(shù)據(jù)更改、acl更改的版本號(hào)的stat結(jié)構(gòu)。該結(jié)構(gòu)也包含時(shí)間戳。版本號(hào)和時(shí)間戳,允許ZooKeeper驗(yàn)證緩存并協(xié)調(diào)更新。
每次節(jié)點(diǎn)的數(shù)據(jù)變更,版本號(hào)都會(huì)自動(dòng),例如,每次客戶端檢索數(shù)據(jù),也會(huì)檢索數(shù)據(jù)的版本號(hào)。當(dāng)客戶端進(jìn)行一個(gè)更新或者刪除操作時(shí),需要提供變更的數(shù)據(jù)的版本號(hào)。如果版本號(hào)不匹配實(shí)際的數(shù)據(jù)版本號(hào),更新操作失敗。


注:Zookeeper中,znode標(biāo)識(shí)數(shù)據(jù)節(jié)點(diǎn),Servers標(biāo)識(shí)組成Zookeeper服務(wù)的機(jī)器。 quorum peers指組成服務(wù)的一個(gè)整體。client指任何使用Zookeeper服務(wù)的主機(jī)或者進(jìn)程

Znodes是開(kāi)發(fā)者訪問(wèn)的主要實(shí)體,需要留意的點(diǎn)很多。

Watches

客戶端可以在znodes上設(shè)置監(jiān)控。節(jié)點(diǎn)上的變更將觸發(fā)監(jiān)控并清除監(jiān)控。當(dāng)一個(gè)監(jiān)控被觸發(fā)后,Zookeeper會(huì)發(fā)送一個(gè)通知在客戶端上。

數(shù)據(jù)訪問(wèn)

一個(gè)命名空間下的每個(gè)節(jié)點(diǎn)的讀和寫都是自動(dòng)的。讀獲取節(jié)點(diǎn)關(guān)聯(lián)的所有數(shù)據(jù),寫替換節(jié)點(diǎn)關(guān)聯(lián)的數(shù)據(jù)。每個(gè)節(jié)點(diǎn)都有一個(gè)控制列表(ACL)來(lái)限制誰(shuí)可以做這些。

Zookeeper不是設(shè)計(jì)用來(lái)作為一個(gè)常規(guī)的數(shù)據(jù)庫(kù)或者大對(duì)象的存儲(chǔ)。相反,它管理協(xié)調(diào)數(shù)據(jù)。這些數(shù)據(jù)可以以配置、狀態(tài)信息、集合等形式出現(xiàn)。各種形式的協(xié)調(diào)數(shù)據(jù)的一個(gè)共同特性是它們相對(duì)較小:以千字節(jié)為單位測(cè)量。ZooKeeper客戶機(jī)和服務(wù)器實(shí)現(xiàn)都進(jìn)行了完整性檢查,以確保znode的數(shù)據(jù)少于1M,但平均數(shù)據(jù)應(yīng)該比這少得多。在相對(duì)較大的數(shù)據(jù)大小上操作將導(dǎo)致某些操作比其他操作花費(fèi)更多的時(shí)間,并且會(huì)影響某些操作的延遲,因?yàn)樾枰~外的時(shí)間將更多的數(shù)據(jù)通過(guò)網(wǎng)絡(luò)轉(zhuǎn)移到存儲(chǔ)介質(zhì)上。如果需要大數(shù)據(jù)存儲(chǔ),通常處理此類數(shù)據(jù)的模式是將其存儲(chǔ)在一個(gè)大存儲(chǔ)系統(tǒng)上,比如NFS或HDFS,并將指向ZooKeeper中存儲(chǔ)位置的指針存儲(chǔ)。

臨時(shí)節(jié)點(diǎn)

ZooKeeper也有臨時(shí)節(jié)點(diǎn)的概念。只要?jiǎng)?chuàng)建znode的會(huì)話處于活動(dòng)狀態(tài),這些znode就會(huì)存在。當(dāng)會(huì)話結(jié)束時(shí),刪除znode。由于這種行為,臨時(shí)znode不允許有子節(jié)點(diǎn)。

序列節(jié)點(diǎn)——惟一命名

在創(chuàng)建znode時(shí),您還可以請(qǐng)求ZooKeeper在路徑的末尾添加一個(gè)單調(diào)遞增的計(jì)數(shù)器。

容器節(jié)點(diǎn)(3.5.3版本增加)

ZooKeeper有容器znode的概念。容器znode是一種特殊用途的znode,可用于菜譜,如leader、lock等。當(dāng)刪除容器的最后一個(gè)子元素時(shí),容器將成為將來(lái)某個(gè)時(shí)候服務(wù)器要?jiǎng)h除的候選對(duì)象。給定此屬性,您應(yīng)該準(zhǔn)備獲取KeeperException。在容器znode內(nèi)創(chuàng)建子節(jié)點(diǎn)時(shí)使用NoNodeException。例如,當(dāng)在容器znodes內(nèi)創(chuàng)建子znode時(shí),總是檢查KeeperException。發(fā)生時(shí)重新創(chuàng)建容器znode。

TTL 節(jié)點(diǎn)(3.5.3版本增加)

在創(chuàng)建持久或持久順序znode時(shí),可以選擇為znode設(shè)置一個(gè)以毫秒為單位的TTL。如果znode沒(méi)有在TTL中進(jìn)行修改,并且沒(méi)有子節(jié)點(diǎn),那么它將成為將來(lái)某個(gè)時(shí)候由服務(wù)器刪除的候選節(jié)點(diǎn)。注意:TTL節(jié)點(diǎn)必須通過(guò)系統(tǒng)屬性啟用,因?yàn)樗鼈冊(cè)谀J(rèn)情況下是禁用的。有關(guān)詳細(xì)信息,請(qǐng)參閱管理員指南。如果您試圖創(chuàng)建沒(méi)有適當(dāng)系統(tǒng)屬性集的TTL節(jié)點(diǎn),服務(wù)器將拋出KeeperException.UnimplementedException。

Time in ZooKeeper

Zookeeper使用多種方式記錄時(shí)間:

  • Zxid:對(duì)ZooKeeper狀態(tài)的每次更改都會(huì)收到一個(gè)zxid (ZooKeeper事務(wù)Id)形式的戳記,這將向ZooKeeper公開(kāi)所有更改的總順序。每個(gè)更改都有一個(gè)惟一的zxid,如果zxid1小于zxid2,則zxid1發(fā)生在zxid2之前。
  • Version numbers:對(duì)節(jié)點(diǎn)的每一次更改都會(huì)導(dǎo)致該節(jié)點(diǎn)的版本號(hào)之一增加。這三個(gè)版本號(hào)是version(對(duì)znode數(shù)據(jù)的更改數(shù)量)、cversion(對(duì)znode子節(jié)點(diǎn)的更改數(shù)量)和hate(對(duì)znode ACL的更改數(shù)量)。
  • Ticks:當(dāng)使用多服務(wù)器ZooKeeper時(shí),服務(wù)器使用ticks來(lái)定義事件的時(shí)間,例如狀態(tài)上傳、會(huì)話超時(shí)、對(duì)等點(diǎn)之間的連接超時(shí)等。Tick時(shí)間僅通過(guò)最小會(huì)話超時(shí)(Tick時(shí)間的2倍)間接公開(kāi);如果客戶機(jī)請(qǐng)求的會(huì)話超時(shí)小于最小會(huì)話超時(shí),服務(wù)器將告訴客戶機(jī)會(huì)話超時(shí)實(shí)際上是最小會(huì)話超時(shí)。
  • Real time:ZooKeeper根本不使用實(shí)時(shí)或時(shí)鐘時(shí)間,除了在znode創(chuàng)建和修改時(shí)將時(shí)間戳放入stat結(jié)構(gòu)之外。

ZooKeeper Stat Structure

每個(gè)節(jié)點(diǎn)的stat結(jié)構(gòu)都由一下字段組成:

  • czxid:節(jié)點(diǎn)創(chuàng)建的zxid變化
  • mzxid:節(jié)點(diǎn)最后修改的zxid的變化
  • pzxid:子節(jié)點(diǎn)最后修改的zxid的變化
  • ctime:節(jié)點(diǎn)創(chuàng)建的微秒形式
  • mtime:節(jié)點(diǎn)最后修改時(shí)間的微秒形式
  • version:節(jié)點(diǎn)數(shù)據(jù)變更的版本號(hào)
  • cversion:子節(jié)點(diǎn)變更的版本號(hào)
  • aversion:節(jié)點(diǎn)Acl變更的版本號(hào)
  • ephemeralOwner:如果節(jié)點(diǎn)是臨時(shí)節(jié)點(diǎn),該字段為節(jié)點(diǎn)的session id,如果是非臨時(shí)節(jié)點(diǎn),為零。
  • dataLength:節(jié)點(diǎn)數(shù)據(jù)字段的長(zhǎng)度
  • numChildren:子節(jié)點(diǎn)的數(shù)據(jù)

Zookeeper Sessions

ZooKeeper客戶端通過(guò)使用語(yǔ)言綁定創(chuàng)建服務(wù)句柄來(lái)與ZooKeeper服務(wù)建立會(huì)話.創(chuàng)建好句柄后,句柄將以連接狀態(tài)啟動(dòng),客戶端庫(kù)將嘗試連接到構(gòu)成ZooKeeper服務(wù)的服務(wù)器之一,此時(shí)它將切換到連接狀態(tài)。在正常操作期間,客戶端句柄將處于這兩種狀態(tài)之一。如果出現(xiàn)不可恢復(fù)的錯(cuò)誤,比如會(huì)話過(guò)期或身份驗(yàn)證失敗,或者應(yīng)用程序顯式關(guān)閉句柄,句柄將移動(dòng)到關(guān)閉狀態(tài)。

要?jiǎng)?chuàng)建一個(gè)客戶端會(huì)話,應(yīng)用程序代碼必須提供一個(gè)連接字符串,其中包含一個(gè)逗號(hào)分隔的host:port對(duì)列表,每個(gè)host:port對(duì)對(duì)應(yīng)于ZooKeeper服務(wù)器(例如“127.0.0.1:4545”或“127.0.0.1:3000、127.0.0.1:3001 127.0.0.1:3002”)。ZooKeeper客戶端庫(kù)將選擇一個(gè)任意的服務(wù)器并嘗試連接到它。如果這個(gè)連接失敗,或者客戶機(jī)由于任何原因與服務(wù)器斷開(kāi)連接,客戶機(jī)將自動(dòng)嘗試列表中的下一個(gè)服務(wù)器,直到(重新)建立連接。

我們?cè)试S客戶端通過(guò)提供一個(gè)新的逗號(hào)分隔的host:port對(duì)列表來(lái)更新連接字符串,每個(gè)host:port對(duì)對(duì)應(yīng)于ZooKeeper服務(wù)器。該函數(shù)調(diào)用一個(gè)概率負(fù)載平衡算法,該算法可能導(dǎo)致客戶端與其當(dāng)前主機(jī)斷開(kāi)連接,目標(biāo)是在新列表中實(shí)現(xiàn)每個(gè)服務(wù)器預(yù)期的統(tǒng)一連接數(shù)。如果客戶端連接到的當(dāng)前主機(jī)不在新列表中,此調(diào)用將始終導(dǎo)致連接被刪除。否則,決策將基于服務(wù)器的數(shù)量是增加了還是減少了.

例如,如果以前的連接字符串包含3臺(tái)主機(jī),而現(xiàn)在列表包含這3臺(tái)主機(jī)和另外2臺(tái)主機(jī),那么連接到這3臺(tái)主機(jī)的40%的客戶端將移動(dòng)到其中一臺(tái)新主機(jī),以平衡負(fù)載。該算法將導(dǎo)致客戶端斷開(kāi)與當(dāng)前主機(jī)的連接,該連接的概率為0.4,在本例中,將導(dǎo)致客戶端連接到隨機(jī)選擇的兩個(gè)新主機(jī)之一。

ZooKeeper Watches

Zookeeper中所有的讀操作,如getData(),getChildren()和exists()-都有一個(gè)設(shè)置監(jiān)控的副作用選項(xiàng)。Zookeeper中的監(jiān)控有三種:one-time trigger,sent to the client 和the data for which the watch was set.
設(shè)置監(jiān)控的三個(gè)要點(diǎn):

  • one time trigger:當(dāng)數(shù)據(jù)變更,一個(gè)監(jiān)控事件將被發(fā)送到客戶端,例如:如果一個(gè)客戶端做了一個(gè)getData("/zsnode1", true),之后/zsnode1節(jié)點(diǎn)的數(shù)據(jù)發(fā)生了變更或者刪除,客戶端將收到一個(gè)監(jiān)聽(tīng)事件。如果再次發(fā)生變更,就沒(méi)有監(jiān)聽(tīng)事件發(fā)送了,除非客戶端做了其他的讀操作設(shè)置里新的監(jiān)控。
  • sent to the client這意味著一個(gè)事件正在發(fā)送到客戶機(jī)的路上,但是可能在成功地將更改操作的返回代碼發(fā)送到發(fā)起更改的客戶機(jī)之前無(wú)法到達(dá)客戶機(jī)。手表以異步方式發(fā)送給觀察者。ZooKeeper提供了一個(gè)訂購(gòu)保證:客戶端在第一次看到watch事件之前,永遠(yuǎn)不會(huì)看到設(shè)置了手表的更改。網(wǎng)絡(luò)延遲或其他因素可能導(dǎo)致不同的客戶端在不同的時(shí)間看到手表并從更新中返回代碼。關(guān)鍵是不同客戶看到的所有東西都有一個(gè)一致的順序。
  • The data for which the watch was set:這指的是節(jié)點(diǎn)更改的不同方式。將ZooKeeper看作是維護(hù)兩個(gè)表列表是有幫助的:數(shù)據(jù)表和子表。getData()和exists()設(shè)置數(shù)據(jù)手表。getChildren()設(shè)置子手表。或者,可以考慮根據(jù)返回的數(shù)據(jù)類型設(shè)置手表。getData()和exists()返回關(guān)于節(jié)點(diǎn)數(shù)據(jù)的信息,而getChildren()返回子節(jié)點(diǎn)的列表。因此,setData()將觸發(fā)正在設(shè)置的znode的數(shù)據(jù)監(jiān)視(假設(shè)設(shè)置成功)。成功的create()將觸發(fā)

手表在客戶機(jī)連接到的ZooKeeper服務(wù)器上本地維護(hù)。這使得手表的設(shè)置、維護(hù)和分派都很輕量。當(dāng)客戶端連接到新服務(wù)器時(shí),將為任何會(huì)話事件觸發(fā)手表。當(dāng)與服務(wù)器斷開(kāi)連接時(shí),將不會(huì)接收到手表。當(dāng)客戶端重新連接時(shí),任何以前注冊(cè)的手表都將重新注冊(cè)并在需要時(shí)觸發(fā)。一般來(lái)說(shuō),這一切都是透明的。有一種情況下可能會(huì)錯(cuò)過(guò)一個(gè)手表:如果創(chuàng)建了znode,則會(huì)錯(cuò)過(guò)一個(gè)尚未創(chuàng)建znode的手表

監(jiān)控的定義

我們可以使用讀取ZooKeeper狀態(tài)的三個(gè)調(diào)用來(lái)設(shè)置手表:exists、getData和getChildren。下面的列表詳細(xì)說(shuō)明了手表可以觸發(fā)的事件以及啟用這些事件的調(diào)用:

  • created 事件: 調(diào)用exists方法會(huì)啟用
  • deleted 事件: 調(diào)用exists,getData,getChildren方法會(huì)啟用
  • changed 事件: 調(diào)用exists,getData方法會(huì)啟用
  • child 事件: 調(diào)用getChildren方法會(huì)啟用

監(jiān)控去除

可以使用removeWatches方法去除節(jié)點(diǎn)上注冊(cè)的監(jiān)控,此外,即使沒(méi)有服務(wù)器連接,ZooKeeper客戶機(jī)也可以通過(guò)將local標(biāo)志設(shè)置為true來(lái)在本地刪除手表。下面的列表詳細(xì)說(shuō)明了成功刪除手表后將觸發(fā)的事件。

  • Child Remove 事件:調(diào)用getChildren方法添加的監(jiān)控
  • Data Remove 事件:調(diào)用exists方法和getData方法添加的監(jiān)控

Zookeeper監(jiān)控的作用

關(guān)于監(jiān)控,Zookeeper維護(hù)一下保證:

  • 根據(jù)其他事件、其他監(jiān)控和異步響應(yīng)對(duì)監(jiān)控。ZooKeeper客戶端庫(kù)確保按順序分派所有內(nèi)容。進(jìn)行排序。ZooKeeper客戶端庫(kù)確保按順序分派所有內(nèi)容。
  • 在看到與該znode對(duì)應(yīng)的新數(shù)據(jù)之前,客戶機(jī)將看到它正在監(jiān)視的znode的監(jiān)視事件。
  • 來(lái)自ZooKeeper的監(jiān)控事件的順序?qū)?yīng)于ZooKeeper服務(wù)所看到的更新的順序。

監(jiān)控事件需要注意的點(diǎn)

  • 監(jiān)控是一次性的,如果你得到一個(gè)監(jiān)控事件,并且在未來(lái)有變更的時(shí)候得到通知,你必須設(shè)置其他的監(jiān)控。
  • 因?yàn)槭直硎且淮涡杂|發(fā)器,并且在獲取事件和發(fā)送獲取手表的新請(qǐng)求之間存在延遲,所以您不能可靠地查看ZooKeeper中節(jié)點(diǎn)發(fā)生的每個(gè)更改。準(zhǔn)備處理znode在獲取事件和再次設(shè)置手表之間多次更改的情況。
  • 對(duì)于給定的通知,監(jiān)視對(duì)象或功能/上下文對(duì)僅觸發(fā)一次。例如,如果為exists注冊(cè)了相同的watch對(duì)象,并且為相同的文件調(diào)用了getData,然后刪除了該文件,那么使用該文件的刪除通知只會(huì)調(diào)用該watch對(duì)象一次。
  • 當(dāng)您斷開(kāi)與服務(wù)器的連接時(shí)(例如,當(dāng)服務(wù)器失敗時(shí)),在重新建立連接之前,您不會(huì)得到任何監(jiān)控。因此,會(huì)話事件被發(fā)送給所有未完成的監(jiān)控處理程序。使用會(huì)話事件進(jìn)入安全模式:斷開(kāi)連接時(shí)不會(huì)接收事件,因此您的流程應(yīng)該在該模式下謹(jǐn)慎地工作。

Zookeeper 使用Acls訪問(wèn)控制

Zookeeper使用Acls來(lái)進(jìn)行節(jié)點(diǎn)的訪問(wèn)控制,其Acl實(shí)現(xiàn)和Unix文件權(quán)限訪問(wèn)非常相似,一個(gè)Zookeeper節(jié)點(diǎn),它使用許可位來(lái)允許/禁止針對(duì)節(jié)點(diǎn)的各種操作以及這些位所應(yīng)用的范圍。不同于標(biāo)準(zhǔn)的Unix權(quán)限控制,一個(gè)Zookeeper節(jié)點(diǎn)node不受user(文件所有者)、group和world(其他)三個(gè)標(biāo)準(zhǔn)范圍的限制。ZooKeeper沒(méi)有znode的所有者的概念。相反,ACL指定與這些id關(guān)聯(lián)的id和權(quán)限集。

還要注意,ACL只適用于特定的znode。尤其是它不適用于兒童。例如,如果/app只能由ip:172.16.16.1讀取,并且/app/status是世界可讀的,則任何人都可以讀取/app/status;ACL不是遞歸的。

ZooKeeper支持可插入的身份驗(yàn)證方案。id使用表單scheme:expression指定,其中scheme是id對(duì)應(yīng)的身份驗(yàn)證方案。該方案定義了一組有效表達(dá)式。例如,ip:172.16.16.1是使用ip方案的地址為172.16.16.1的主機(jī)的id,而digest:bob:password是使用摘要方案的用戶的id,其名稱為bob。

當(dāng)一個(gè)客戶端連接到ZooKeeper并進(jìn)行身份驗(yàn)證時(shí),ZooKeeper會(huì)將對(duì)應(yīng)于該客戶端的所有id與客戶端連接相關(guān)聯(lián)。當(dāng)客戶端試圖訪問(wèn)節(jié)點(diǎn)時(shí),將對(duì)照z node的ACl檢查這些id。ACL由成對(duì)的(方案:表達(dá)式、置換)組成。表達(dá)式的格式特定于方案。例如,該對(duì)(ip:19.22.0.0/16,READ)向以19.22開(kāi)頭的任何客戶端授予READ權(quán)限。

ACL 權(quán)限

Zookeeper支持一下權(quán)限

  • create:可以創(chuàng)建一個(gè)子節(jié)點(diǎn)
  • read:可以從節(jié)點(diǎn)上獲取數(shù)據(jù)并且列出其子節(jié)點(diǎn)
  • write:可以設(shè)置節(jié)點(diǎn)的數(shù)據(jù)
  • delete:可以刪除一個(gè)子節(jié)點(diǎn)
  • admin:可以設(shè)置權(quán)限
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容