摘要:與此同時(shí),小組也一同致力于項(xiàng)目,參與了很多動(dòng)物命名的項(xiàng)目,其中有廣為人知的項(xiàng)目。主控服務(wù)器將所有更新操作序列化,利用協(xié)議將數(shù)據(jù)更新請(qǐng)求通知所有從屬服務(wù)器,保證更新操作。在術(shù)語(yǔ)下,節(jié)點(diǎn)被稱為。命名為的,由系統(tǒng)自動(dòng)生成,用配額管理。
ZooKeeper 介紹
ZooKeeper(wiki,home,github) 是用于分布式應(yīng)用的開(kāi)源的分布式協(xié)調(diào)服務(wù)。通過(guò)暴露簡(jiǎn)單的原語(yǔ),分布式應(yīng)用能在之上構(gòu)建更高層的服務(wù),如同步、配置管理和組成員管理等。在設(shè)計(jì)上易于編程開(kāi)發(fā),并且數(shù)據(jù)模型使用了熟知的文件系統(tǒng)目錄樹(shù)結(jié)構(gòu) [doc ]。
共識(shí)與 Paxos在介紹 ZooKeeper 之前,有必要了解下 Paxos 和 Chubby。2006 年 Google 在 OSDI 發(fā)表關(guān)于 Bigtable 和 Chubby 的兩篇會(huì)議論文,之后再在 2007 年 PODC 會(huì)議上發(fā)表了論文“Paxos Made Live”,介紹 Chubby 底層實(shí)現(xiàn)的共識(shí)(consensus)協(xié)議 Multi-Paxos,該協(xié)議對(duì) Lamport 的原始 Paxos 算法做了改進(jìn),提高了運(yùn)行效率 [ref ]。Chubby 作為鎖服務(wù)被 Google 應(yīng)用在 GFS 和 Bigtable 中。受 Chubby 的影響,來(lái)自 Yahoo 研究院的 Benjamin Reed 和 Flavio Junqueira 等人開(kāi)發(fā)了被業(yè)界稱為開(kāi)源版的 Chubby 的 ZooKeeper(內(nèi)部實(shí)現(xiàn)事實(shí)上稍有不同 [ref ]),底層的共識(shí)協(xié)議為 ZAB。Lamport 的 Paxos 算法出了名的難懂,如何讓算法更加可理解(understandable),便成了 Stanford 博士生 Diego Ongaro 的研究課題。Diego Ongaro 在 2014 年發(fā)表了介紹 Raft 算法的論文,“In search of an understandable consensus algorithm”。Raft 是可理解版的 Paxos,很快就成為解決共識(shí)問(wèn)題的流行協(xié)議之一。這些類 Paxos 協(xié)議和 Paxos 系統(tǒng)之間的關(guān)系,如下 [Ailijiang2016 ]:
Google 的 Chubby 沒(méi)有開(kāi)源,在云計(jì)算和大數(shù)據(jù)技術(shù)的風(fēng)口下,Yahoo 開(kāi)源的 ZooKeeper 便在工業(yè)界流行起來(lái)。ZooKeeper 重要的時(shí)間線如下:
2007 年 11 月 ZooKeeper 1.0 在 SourceForge 上發(fā)布 [ref ]
2008 年 6 月開(kāi)始從 SourceForge 遷移到 Apache [ref ],在 10 月 Zookeeper 3.0 發(fā)布,并成為 Hadoop 的子項(xiàng)目 [ref1 ref2 ]
關(guān)于 ZooKeeper 名字的來(lái)源,F(xiàn)lavio Junqueira 和 Benjamin Reed 在介紹 ZooKeeper 的書中有如下闡述:
ZooKeeper 由雅虎研究院開(kāi)發(fā)。我們小組在進(jìn)行 ZooKeeper 的開(kāi)發(fā)一段時(shí)間之后,開(kāi)始推薦給其他小組,因此我們需要為我們的項(xiàng)目起一個(gè)名字。與此同時(shí),小組也一同致力于 Hadoop 項(xiàng)目,參與了很多動(dòng)物命名的項(xiàng)目,其中有廣為人知的 Apache Pig 項(xiàng)目(http://pig.apache.org)。我們?cè)谟懻摳鞣N各樣的名字時(shí),一位團(tuán)隊(duì)成員提到我們不能再使用動(dòng)物的名字了,因?yàn)槲覀兊闹鞴苡X(jué)得這樣下去會(huì)覺(jué)得我們生活在動(dòng)物園中。大家對(duì)此產(chǎn)生了共鳴,分布式系統(tǒng)就像一個(gè)動(dòng)物園,混亂且難以管理,而 ZooKeeper 就是將這一切變得可控。體系結(jié)構(gòu)
ZooKeeper 服務(wù)由若干臺(tái)服務(wù)器構(gòu)成,其中的一臺(tái)通過(guò) ZAB 原子廣播協(xié)議選舉作為主控服務(wù)器(leader),其他的作為從屬服務(wù)器(follower)。客戶端可以通過(guò) TCP 協(xié)議連接任意一臺(tái)服務(wù)器。如果客戶端是讀操作請(qǐng)求,則任意一個(gè)服務(wù)器都可以直接響應(yīng)請(qǐng)求;如果是更新數(shù)據(jù)操作(寫數(shù)據(jù)或者更新數(shù)據(jù))。則只能由主控服務(wù)器來(lái)協(xié)調(diào)更新操作;如果客戶端連接的是從屬服務(wù)器,則從屬服務(wù)器會(huì)將更新?lián)?qǐng)求轉(zhuǎn)發(fā)到主控服務(wù)器,由其完成更新操作。主控服務(wù)器將所有更新操作序列化,利用 ZAB 協(xié)議將數(shù)據(jù)更新請(qǐng)求通知所有從屬服務(wù)器,ZAB 保證更新操作。
讀和寫操作,如下圖所示 [Haloi2015 ]:
ZooKeeper 的任意一臺(tái)服務(wù)器都可以響應(yīng)客戶端的讀操作,這樣可以提高吞吐量。Chubby 在這點(diǎn)上與 ZooKeeper 不同,所有讀/寫操作都由主控服務(wù)器完成,從屬服務(wù)器只是為了提高整個(gè)協(xié)調(diào)系統(tǒng)的可用性,即主控服務(wù)器發(fā)生故障后能夠在從屬服務(wù)器中快速選舉出新的主控服務(wù)器。在帶來(lái)高吞吐量?jī)?yōu)勢(shì)的同時(shí),ZooKeeper 這樣做也帶來(lái)潛在的問(wèn)題:客戶端可能會(huì)讀到過(guò)期數(shù)據(jù),因?yàn)榧词怪骺胤?wù)器已經(jīng)更新了某個(gè)內(nèi)存數(shù)據(jù),但是 ZAB 協(xié)議還未能將其廣播到從屬服務(wù)器。為了解決這一問(wèn)題,在 ZooKeeper 的接口 API 函數(shù)中提供了 sync 操作,應(yīng)用可以根據(jù)需要在讀數(shù)據(jù)前調(diào)用該操作,其含義是:接收到 sync 命令的從屬服務(wù)器從主控服務(wù)器同步狀態(tài)信息,保證兩者完全一致。這樣如果在讀操作前調(diào)用 sync 操作,則可以保證客戶端一定可以讀取到最新?tīng)顟B(tài)的數(shù)據(jù)。
數(shù)據(jù)模型ZooKeeper 所提供的命名空間跟標(biāo)準(zhǔn)文件系統(tǒng)很相似。路徑中一系列元素是用斜杠(/)分隔的。每個(gè)節(jié)點(diǎn)在 ZooKeper 命名空間中是用路徑來(lái)識(shí)別的。在 ZooKeeper 術(shù)語(yǔ)下,節(jié)點(diǎn)被稱為 znode。默認(rèn)每個(gè) znode 最大只能存儲(chǔ) 1M 數(shù)據(jù)(可以通過(guò)配置參數(shù)修改),這與 Chubby 一樣是出于避免應(yīng)用將協(xié)調(diào)系統(tǒng)當(dāng)作存儲(chǔ)系統(tǒng)來(lái)用。znode 只能使用絕對(duì)路徑,相對(duì)路徑不能被 ZooKeeper 識(shí)別。znode 命名可以是任意 Unicode 字符。唯一的例外是,名稱"/zookeeper"。命名為"/zookeeper"的 znode,由 ZooKeeper 系統(tǒng)自動(dòng)生成,用配額(quota)管理。
ZooKeeper 使用 安裝與配置ZooKeeper 安裝與啟動(dòng):
$ brew info zookeeper zookeeper: stable 3.4.10 (bottled), HEAD Centralized server for distributed coordination of services https://zookeeper.apache.org/ ... 省略 $ brew install zookeeper $ zkServer start # 啟動(dòng) $ zkServer stop # 終止 $ zkServer help ZooKeeper JMX enabled by default Using config: /usr/local/etc/zookeeper/zoo.cfg Usage: ./zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd}
若不修改配置文件,默認(rèn)是單機(jī)模式啟動(dòng)。若要使用集群模式,需要修改 /usr/local/etc/zookeeper/zoo.cfg(默認(rèn)路徑)。示例 zoo.cfg [doc ]:
tickTime=2000 dataDir=/var/lib/zookeeper clientPort=2181 initLimit=5 syncLimit=2 server.1=192.168.211.11:2888:3888 server.2=192.168.211.12:2888:3888 server.3=192.168.211.13:2888:3888
clientPort:客戶端連接 Zookeeper 服務(wù)器的端口,Zookeeper 會(huì)監(jiān)聽(tīng)這個(gè)端口,接受客戶端的訪問(wèn)請(qǐng)求。
server.X=YYY:A:B
X:表示的服務(wù)器編號(hào);
YYY:表示服務(wù)器的ip地址;
A:表示服務(wù)器節(jié)點(diǎn)間的通信端口,用于 follower 和 leader 節(jié)點(diǎn)的通信;
B:表示選舉端口,表示選舉新 leader 時(shí)服務(wù)器間相互通信的端口,當(dāng) leader 掛掉時(shí),其余服務(wù)器會(huì)相互通信,選擇出新的 leader。
若想在單臺(tái)主機(jī)上試驗(yàn)集群模式,可以將 YYY 都修改為 localhost,并且讓兩個(gè)端口 A:B 也相互不同(比如:2888:3888, 2889:3889, 2890:3890),即可實(shí)現(xiàn)偽集群模式。示例 zoo.cfg 如下 [doc ]:
server.1=localhost:2888:3888 server.2=localhost:2889:3889 server.3=localhost:2890:3890
zkCli 支持的全部命令:
$ zkCli help ZooKeeper -server host:port cmd args stat path [watch] set path data [version] ls path [watch] delquota [-n|-b] path ls2 path [watch] setAcl path acl setquota -n|-b val path history redo cmdno printwatches on|off delete path [version] sync path listquota path rmr path get path [watch] create [-s] [-e] path data acl addauth scheme auth quit getAcl path close connect host:port節(jié)點(diǎn)類型及其操作
Zookeeper 支持兩種類型節(jié)點(diǎn):持久節(jié)點(diǎn)(persistent znode)和臨時(shí)節(jié)點(diǎn)(ephemeral znode)。持久節(jié)點(diǎn)不論客戶端會(huì)話情況,一直存在,只有當(dāng)客戶端顯式調(diào)用刪除操作才會(huì)消失。而臨時(shí)節(jié)點(diǎn)則不同,會(huì)在客戶端會(huì)話結(jié)束或者發(fā)生故障的時(shí)候被 ZooKeeper 系統(tǒng)自動(dòng)清除。另外,這兩種類型的節(jié)點(diǎn)都可以添加是否是順序(sequential)的特性,這樣就有了:持久順序節(jié)點(diǎn)和臨時(shí)順序節(jié)點(diǎn)。
(1) 持久節(jié)點(diǎn)(persistent znode)
使用 create 創(chuàng)建節(jié)點(diǎn)(默認(rèn)持久節(jié)點(diǎn)),以及使用 get 查看該節(jié)點(diǎn):
$ zkCli # 啟動(dòng)客戶端 [zk: localhost:2181(CONNECTED) 1] create /zoo "hello zookeeper" Created /zoo [zk: localhost:2181(CONNECTED) 2] get /zoo hello zookeeper cZxid = 0x8d ctime = Thu Nov 08 20:42:55 CST 2017 mZxid = 0x8d mtime = Thu Nov 08 20:42:55 CST 2017 pZxid = 0x8d cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 15 numChildren = 0
create 創(chuàng)建子節(jié)點(diǎn),以及使用 ls 查看全部子節(jié)點(diǎn):
[zk: localhost:2181(CONNECTED) 3] create /zoo/duck "" Created /zoo/duck [zk: localhost:2181(CONNECTED) 4] create /zoo/goat "" Created /zoo/goat [zk: localhost:2181(CONNECTED) 5] create /zoo/cow "" Created /zoo/cow [zk: localhost:2181(CONNECTED) 6] ls /zoo [cow, goat, duck]
delete 刪除節(jié)點(diǎn),以及使用 rmr 遞歸刪除:
[zk: localhost:2181(CONNECTED) 7] delete /zoo/duck [zk: localhost:2181(CONNECTED) 8] ls /zoo [cow, goat] [zk: localhost:2181(CONNECTED) 9] delete /zoo Node not empty: /zoo [zk: localhost:2181(CONNECTED) 10] rmr /zoo [zk: localhost:2181(CONNECTED) 11] ls /zoo Node does not exist: /zoo
(2) 臨時(shí)節(jié)點(diǎn)(ephemeral znode)
和持久節(jié)點(diǎn)不同,臨時(shí)節(jié)點(diǎn)不能創(chuàng)建子節(jié)點(diǎn):
$ zkCli # 啟動(dòng)第1個(gè)客戶端 [zk: localhost:2181(CONNECTED) 0] create -e /node "hello" Created /node [zk: localhost:2181(CONNECTED) 40] get /node hello cZxid = 0x97 ctime = Thu Nov 08 21:01:25 CST 2017 mZxid = 0x97 mtime = Thu Nov 08 21:01:25 CST 2017 pZxid = 0x97 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x161092a0ff30000 dataLength = 5 numChildren = 0 [zk: localhost:2181(CONNECTED) 1] create /node/child "" Ephemerals cannot have children: /node/child
臨時(shí)節(jié)點(diǎn)在客戶端會(huì)話結(jié)束或者發(fā)生故障的時(shí)候被 ZooKeeper 系統(tǒng)自動(dòng)清除。現(xiàn)在試驗(yàn)下的針對(duì)臨時(shí)節(jié)點(diǎn)自動(dòng)清除的監(jiān)視:
$ zkCli # 啟動(dòng)第2個(gè)客戶端 [zk: localhost:2181(CONNECTED) 0] create -e /node "hello" Node already exists: /node [zk: localhost:2181(CONNECTED) 1] stat /node true cZxid = 0x97 ctime = Thu Nov 08 21:01:25 CST 2017 mZxid = 0x97 mtime = Thu Nov 08 21:01:25 CST 2017 pZxid = 0x97 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x161092a0ff30000 dataLength = 5 numChildren = 0
若客戶端1,退出 quit 或崩潰,客戶端2將收到監(jiān)視事件:
[zk: localhost:2181(CONNECTED) 2] WATCHER:: WatchedEvent state:SyncConnected type:NodeDeleted path:/node
(3) 順序節(jié)點(diǎn)(sequential znode)
順序節(jié)點(diǎn)在其創(chuàng)建時(shí) ZooKeeper 會(huì)自動(dòng)在 znode 名稱上附加上順序編號(hào)。順序編號(hào),由父 znode 維護(hù),并且單調(diào)遞增。順序編號(hào),由 4 字節(jié)的有符號(hào)整數(shù)組成,并被格式化為 0 填充的 10 位數(shù)字。
[zk: localhost:2181(CONNECTED) 1] create /test "" Created /test [zk: localhost:2181(CONNECTED) 2] create -s /test/seq "" Created /test/seq0000000000 [zk: localhost:2181(CONNECTED) 3] create -s /test/seq "" Created /test/seq0000000001 [zk: localhost:2181(CONNECTED) 4] create -s /test/seq "" Created /test/seq0000000002 [zk: localhost:2181(CONNECTED) 5] ls /test [seq0000000000, seq0000000001, seq0000000002]客戶端 API
ZooKeeper 提供的主要 znode 操作 API 如下表所示:
API 操作 | 描述 | CLI 命令 |
---|---|---|
create | 創(chuàng)建 znode | create |
delete | 刪除 znode | delete/rmr/delquota |
exists | 檢查 znode 是否存在 | stat |
getChildren | 讀取 znode 全部的子節(jié)點(diǎn) | ls/ls2 |
getData | 讀取 znode 數(shù)據(jù) | get/listquota |
setData | 設(shè)置 znode 數(shù)據(jù) | set/setquota |
getACL | 讀取 znode 的 ACL | getACL |
setACL | 設(shè)置 znode 的 ACL | setACL |
sync | 同步 | sync |
Java 的 ZooKeeper 類實(shí)現(xiàn)了上述提供的 API。
Zookeeper 底層是 Java 實(shí)現(xiàn),zkCli 命令行工具底層也是 Java 實(shí)現(xiàn),對(duì)應(yīng)的 Java 實(shí)現(xiàn)類為 org.apache.zookeeper.ZooKeeperMain [src1 src2 ]。ZooKeeper 3.5.x 下,CLI 命令與底層實(shí)現(xiàn) API 對(duì)應(yīng)關(guān)系:
命名 CLI | Java API (ZooKeeper 類) |
---|---|
addauth scheme auth | public void addAuthInfo(String scheme, byte[] auth) |
close | public void close() |
create [-s] [-e] path data acl | public String create(final String path, byte data[], List |
delete path [version] | public void delete(String path, int version) |
delquota [-n|-b] path | public void delete(String path, int version) |
get path [watch] | public byte[] getData(String path, boolean watch, Stat stat) |
getAcl path | public List |
listquota path | public byte[] getData(String path, boolean watch, Stat stat) |
ls path [watch] | public List |
ls2 path [watch] | - |
quit | public void close() |
rmr path | public void delete(final String path, int version) |
set path data [version] | public Stat setData(String path, byte[] data, int version) |
setAcl path acl | public Stat setACL(final String path, List |
setquota -n|-b val path | public Stat setData(String path, byte[] data, int version) |
stat path [watch] | public Stat exists(String path, boolean watch) |
sync path | public void sync(String path, AsyncCallback.VoidCallback cb, Object ctx) |
ZooKeeper 提供了處理變化的重要機(jī)制一一監(jiān)視點(diǎn)(watch)。通過(guò)監(jiān)視點(diǎn),客戶端可以對(duì)指定的 znode 節(jié)點(diǎn)注冊(cè)一個(gè)通知請(qǐng)求,在發(fā)生變化時(shí)就會(huì)收到一個(gè)單次的通知。當(dāng)應(yīng)用程序注冊(cè)了一個(gè)監(jiān)視點(diǎn)來(lái)接收通知,匹配該監(jiān)視點(diǎn)條件的第一個(gè)事件會(huì)觸發(fā)監(jiān)視點(diǎn)的通知,并且最多只觸發(fā)一次。例如,當(dāng) znode 節(jié)點(diǎn)也被刪除,客戶端需要知道該變化,客戶端在 /z 節(jié)點(diǎn)執(zhí)行 exists 操作并設(shè)置監(jiān)視點(diǎn)標(biāo)志位,等待通知,客戶端會(huì)以回調(diào)函數(shù)的形式收到通知。
ZooKeeper 的 API 中的讀操作:getData、getChildren 和 exists,均可以選擇在讀取的 znode 節(jié)點(diǎn)上設(shè)置監(jiān)視點(diǎn)。使用監(jiān)視點(diǎn)機(jī)制,我們需要實(shí)現(xiàn) Watcher 接口類,該接口唯一方法為 process:
void process(WatchedEvent event)
WatchedEvent 數(shù)據(jù)結(jié)構(gòu)包括以下信息:
ZooKeeper會(huì)話狀態(tài)(KeeperState):Disconnected、SyncConnected、AuthFailed、ConnectedReadOnly 、SaslAuthenticated、Expired。
事件類型(EventType):NodeCreated 、NodeDeleted 、NodeDataChanged、NodeChildrenChanged 和 None 。
若事件類型不是 None,還包括 znode 路徑。
若收到 WatchedEvent, 在 zkCli 中會(huì)輸出類似如下結(jié)果:
WatchedEvent state:SyncConnected type:NodeDeleted path:/node
監(jiān)視點(diǎn)有兩種類型:數(shù)據(jù)監(jiān)視點(diǎn)和子節(jié)點(diǎn)監(jiān)視點(diǎn)。創(chuàng)建、刪除或設(shè)置一個(gè) znode 節(jié)點(diǎn)的數(shù)據(jù)都會(huì)觸發(fā)數(shù)據(jù)監(jiān)視點(diǎn),exists 和 getData 這兩個(gè)操作可以設(shè)置數(shù)據(jù)監(jiān)視點(diǎn)。只有 getChildren 操作可以設(shè)置子節(jié)點(diǎn)監(jiān)視點(diǎn),這種監(jiān)視點(diǎn)只有在 znode 子節(jié)點(diǎn)創(chuàng)建或刪除時(shí)才被觸發(fā)。對(duì)于每種事件類型,我們通過(guò)以下調(diào)用設(shè)置監(jiān)視點(diǎn):
NodeCreated
???通過(guò) exists 調(diào)用設(shè)置一個(gè)監(jiān)視點(diǎn)。
NodeDeleted
???通過(guò) exists 或 getData 調(diào)用設(shè)置監(jiān)視點(diǎn)。
NodeDataChanged
???通過(guò) exists 或getData 調(diào)用設(shè)置監(jiān)視點(diǎn)。
NodeChildrenChanged
???通過(guò) getChildren 調(diào)用設(shè)置監(jiān)視點(diǎn)。
在 Java 下使用 ZooKeeper 需要先添加如下 maven 依賴:
org.apache.zookeeper zookeeper 3.4.11 pom
ZookeeperDemo 示例,展示了建立連接會(huì)話,以及對(duì) znode 的創(chuàng)建、讀取、修改、刪除和設(shè)置監(jiān)視點(diǎn)等操作:
import java.io.IOException; import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.zookeeper.*; import org.apache.zookeeper.data.Stat; public class ZookeeperDemo { public static void main(String[] args) throws KeeperException, InterruptedException, IOException { // 創(chuàng)建服務(wù)器連接 ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 100, new Watcher() { // 監(jiān)控所有被觸發(fā)的事件 public void process(WatchedEvent event) { System.out.printf("WatchedEvent state:%s type:%s path:%s ", event.getState(), event.getType(), event.getPath()); } }); // 創(chuàng)建節(jié)點(diǎn) zk.create("/zoo", "hello ZooKeeper".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); // 讀取節(jié)點(diǎn)數(shù)據(jù) Stat stat = new Stat(); System.out.println(new String(zk.getData("/zoo", false, stat))); printStat(stat); // 創(chuàng)建子節(jié)點(diǎn) zk.create("/zoo/duck", "hello duck".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); zk.create("/zoo/goat", "hello goat".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); zk.create("/zoo/cow", "hello cow".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); // 讀取子節(jié)點(diǎn)列表,并設(shè)置監(jiān)視點(diǎn) System.out.println(zk.getChildren("/zoo", true)); // 讀取子節(jié)點(diǎn)數(shù)據(jù),并設(shè)置監(jiān)視點(diǎn) System.out.println(new String(zk.getData("/zoo/duck", true, null))); // 修改子節(jié)點(diǎn)數(shù)據(jù) zk.setData("/zoo/duck", "hi duck".getBytes(), -1); // 讀取修改后的子節(jié)點(diǎn)數(shù)據(jù) System.out.println(new String(zk.getData("/zoo/duck", true, null))); // 刪除子節(jié)點(diǎn) zk.delete("/zoo/duck", -1); zk.delete("/zoo/goat", -1); zk.delete("/zoo/cow", -1); // 刪除父節(jié)點(diǎn) zk.delete("/zoo", -1); // 關(guān)閉連接 zk.close(); } private static void printStat(Stat stat) { System.out.println("cZxid = 0x" + Long.toHexString(stat.getCzxid())); System.out.println("ctime = " + DateFormatUtils.format(stat.getCtime(), "yyyy-MM-dd HH:mm:ss")); System.out.println("mZxid = 0x" + Long.toHexString(stat.getMzxid())); System.out.println("mtime = " + DateFormatUtils.format(stat.getMtime(), "yyyy-MM-dd HH:mm:ss")); System.out.println("pZxid = 0x" + Long.toHexString(stat.getPzxid())); System.out.println("cversion = " + stat.getCversion()); System.out.println("dataVersion = " + stat.getVersion()); System.out.println("aclVersion = " + stat.getAversion()); System.out.println("ephemeralOwner = 0x" + Long.toHexString(stat.getEphemeralOwner())); System.out.println("dataLength = " + stat.getDataLength()); System.out.println("numChildren = " + stat.getNumChildren()); } }
輸出結(jié)果:
WatchedEvent state:SyncConnected type:None path:null hello ZooKeeper cZxid = 0x1e1 ctime = 2017-11-20 12:18:36 mZxid = 0x1e1 mtime = 2017-11-20 12:18:36 pZxid = 0x1e1 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 15 numChildren = 0 [cow, goat, duck] hello duck WatchedEvent state:SyncConnected type:NodeDataChanged path:/zoo/duck hi duck WatchedEvent state:SyncConnected type:NodeDeleted path:/zoo/duck WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/zooZooInspector
ZooInspector 是 ZooKeeper 3.3.0 開(kāi)始官方提供的可視化查看和編輯 ZooKeeper 實(shí)例的工具 [ZOOKEEPER-678 ]。源碼位于目錄 src/contrib/zooinspector 下,GitHub 地址為:link。可以根據(jù) README.txt 的說(shuō)明運(yùn)行使用。或者可以直接用 ZOOKEEPER-678 下提供的可執(zhí)行 jar 包。
參考資料官方文檔:ZooKeeper http://zookeeper.apache.org/d...
2010-11 許令波:分布式服務(wù)框架 Zookeeper https://www.ibm.com/developer...
ZooKeeper:分布式過(guò)程協(xié)同技術(shù)詳解,Benjamin Reed & Flavio Junqueira,2013,豆瓣
Apache ZooKeeper Essentials, Haloi 2015,豆瓣
從Paxos到Zookeeper,阿里倪超 2015,豆瓣
大數(shù)據(jù)日知錄:架構(gòu)與算法,張俊林 2014,第5章 分布式協(xié)調(diào)系統(tǒng),豆瓣
2010,Patrick Hunt, Mahadev Konar, Flavio Paiva Junqueira, Benjamin Reed: ZooKeeper: Wait-free Coordination for Internet-scale Systems. USENIX ATC 2010,dblp,msa,usenix
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/74712.html
摘要:可靠性一旦數(shù)據(jù)更新成功,將一直保持,直到新的更新。這是一種主動(dòng)的分布式數(shù)據(jù)結(jié)構(gòu),能夠在外部情況發(fā)生變化時(shí)候主動(dòng)修改數(shù)據(jù)項(xiàng)狀態(tài)的數(shù)據(jù)機(jī)構(gòu)。如果監(jiān)視節(jié)點(diǎn)狀態(tài)發(fā)生變化,則跳轉(zhuǎn)到第步,繼續(xù)進(jìn)行后續(xù)的操作,直到退出鎖競(jìng)爭(zhēng)。 題外話:從字面上來(lái)看,ZooKeeper表示動(dòng)物園管理員,而Hadoop生態(tài)系統(tǒng)中,許多項(xiàng)目的Logo都采用了動(dòng)物,比如Hadoop采用了大象的形象,所以可以ZooKeepe...
摘要:相關(guān)概念協(xié)議高級(jí)消息隊(duì)列協(xié)議是一個(gè)標(biāo)準(zhǔn)開(kāi)放的應(yīng)用層的消息中間件協(xié)議。可以用命令與不同,不是線程安全的。手動(dòng)提交執(zhí)行相關(guān)邏輯提交注意點(diǎn)將寫成單例模式,有助于減少端占用的資源。自身是線程安全的類,只要封裝得當(dāng)就能最恰當(dāng)?shù)陌l(fā)揮好的作用。 本文使用的Kafka版本0.11 先思考些問(wèn)題: 我想分析一下用戶行為(pageviews),以便我能設(shè)計(jì)出更好的廣告位 我想對(duì)用戶的搜索關(guān)鍵詞進(jìn)行統(tǒng)計(jì),...
閱讀 1912·2021-11-24 09:39
閱讀 2140·2021-09-22 15:50
閱讀 2009·2021-09-22 14:57
閱讀 705·2021-07-28 00:13
閱讀 1068·2019-08-30 15:54
閱讀 2362·2019-08-30 15:52
閱讀 2688·2019-08-30 13:07
閱讀 3791·2019-08-30 11:27