便捷搭建 Zookeeper 服務(wù)器的方法
什么是 ZooKeeper
ZooKeeper 是 Apache 的一個(gè)頂級(jí)項(xiàng)目,為分布式應(yīng)用提供高效、高可用的分布式協(xié)調(diào)服務(wù),提供了諸如數(shù)據(jù)發(fā)布/訂閱、負(fù)載均衡、命名服務(wù)、分布式協(xié)調(diào)/通知和分布式鎖等分布式基礎(chǔ)服務(wù)。由于 ZooKeeper 便捷的使用方式、卓越的性能和良好的穩(wěn)定性,被廣泛地應(yīng)用于諸如 Hadoop、HBase、Kafka 和 Dubbo 等大型分布式系統(tǒng)中。
Zookeeper 有三種運(yùn)行模式:?jiǎn)螜C(jī)模式、偽集群模式和集群模式。
單機(jī)模式:這種模式一般適用于開發(fā)測(cè)試環(huán)境,一方面我們沒有那么多機(jī)器資源,另外就是平時(shí)的開發(fā)調(diào)試并不需要極好的穩(wěn)定性。 集群模式:一個(gè) ZooKeeper 集群通常由一組機(jī)器組成,一般 3 臺(tái)以上就可以組成一個(gè)可用的 ZooKeeper 集群了。組成 ZooKeeper 集群的每臺(tái)機(jī)器都會(huì)在內(nèi)存中維護(hù)當(dāng)前的服務(wù)器狀態(tài),并且每臺(tái)機(jī)器之間都會(huì)互相保持通信。 偽集群模式:這是一種特殊的集群模式,即集群的所有服務(wù)器都部署在一臺(tái)機(jī)器上。當(dāng)你手頭上有一臺(tái)比較好的機(jī)器,如果作為單機(jī)模式進(jìn)行部署,就會(huì)浪費(fèi)資源,這種情況下,ZooKeeper 允許你在一臺(tái)機(jī)器上通過啟動(dòng)不同的端口來啟動(dòng)多個(gè) ZooKeeper 服務(wù)實(shí)例,以此來以集群的特性來對(duì)外服務(wù)。
ZooKeeper 的相關(guān)知識(shí)
Zookeeper 中的角色:
領(lǐng)導(dǎo)者(leader):負(fù)責(zé)進(jìn)行投票的發(fā)起和決議,更新系統(tǒng)狀態(tài)。 跟隨者(follower):用于接收客戶端請(qǐng)求并給客戶端返回結(jié)果,在選主過程中進(jìn)行投票。 觀察者(observer):可以接受客戶端連接,將寫請(qǐng)求轉(zhuǎn)發(fā)給 leader,但是observer 不參加投票的過程,只是為了擴(kuò)展系統(tǒng),提高讀取的速度。

Zookeeper 的數(shù)據(jù)模型
層次化的目錄結(jié)構(gòu),命名符合常規(guī)文件系統(tǒng)規(guī)范,類似于 Linux。 每個(gè)節(jié)點(diǎn)在 Zookeeper 中叫做 Znode,并且其有一個(gè)唯一的路徑標(biāo)識(shí)。 節(jié)點(diǎn) Znode 可以包含數(shù)據(jù)和子節(jié)點(diǎn),但是 EPHEMERAL 類型的節(jié)點(diǎn)不能有子節(jié)點(diǎn)。 Znode 中的數(shù)據(jù)可以有多個(gè)版本,比如某一個(gè)路徑下存有多個(gè)數(shù)據(jù)版本,那么查詢這個(gè)路徑下的數(shù)據(jù)就需要帶上版本。 客戶端應(yīng)用可以在節(jié)點(diǎn)上設(shè)置監(jiān)視器。 節(jié)點(diǎn)不支持部分讀寫,而是一次性完整讀寫。

ZooKeeper 的節(jié)點(diǎn)特性
ZooKeeper 節(jié)點(diǎn)是生命周期的,這取決于節(jié)點(diǎn)的類型。在 ZooKeeper 中,節(jié)點(diǎn)根據(jù)持續(xù)時(shí)間可以分為持久節(jié)點(diǎn)(PERSISTENT)、臨時(shí)節(jié)點(diǎn)(EPHEMERAL),根據(jù)是否有序可以分為順序節(jié)點(diǎn)(SEQUENTIAL)、和無序節(jié)點(diǎn)(默認(rèn)是無序的)。
Zookeeper 的應(yīng)用場(chǎng)景
數(shù)據(jù)發(fā)布與訂閱(配置中心)
負(fù)載均衡
命名服務(wù)(Naming Service)
服務(wù)提供者在啟動(dòng)的時(shí)候,向 ZooKeeper 上的指定節(jié)點(diǎn) /dubbo/${serviceName}/providers 目錄下寫入自己的 URL 地址,這個(gè)操作就完成了服務(wù)的發(fā)布。 服務(wù)消費(fèi)者啟動(dòng)的時(shí)候,訂閱 /dubbo/${serviceName}/providers 目錄下的提供者 URL 地址, 并向 /dubbo/${serviceName} /consumers 目錄下寫入自己的 URL 地址。
分布式通知/協(xié)調(diào)
分布式鎖
由于同一節(jié)點(diǎn)下子節(jié)點(diǎn)名稱不能相同,所以只要在某個(gè)節(jié)點(diǎn)下創(chuàng)建 Znode,創(chuàng)建成功即表明加鎖成功。注冊(cè)監(jiān)聽器監(jiān)聽此 Znode,只要?jiǎng)h除此 Znode 就通知其他客戶端來加鎖。 創(chuàng)建臨時(shí)順序節(jié)點(diǎn):在某個(gè)節(jié)點(diǎn)下創(chuàng)建節(jié)點(diǎn),來一個(gè)請(qǐng)求則創(chuàng)建一個(gè)節(jié)點(diǎn),由于是順序的,所以序號(hào)最小的獲得鎖,當(dāng)釋放鎖時(shí),通知下一序號(hào)獲得鎖。
分布式隊(duì)列
文件的目錄結(jié)構(gòu)如下:
├──?docker-compose.ymlversion: '3.4'
services:
??zoo1:
????image: zookeeper
????restart: always
????hostname: zoo1
????ports:
??????- 2181:2181
????environment:
??????ZOO_MY_ID: 1
??????ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
??zoo2:
????image: zookeeper
????restart: always
????hostname: zoo2
????ports:
??????- 2182:2181
????environment:
??????ZOO_MY_ID: 2
??????ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zoo3:2888:3888;2181
??zoo3:
????image: zookeeper
????restart: always
????hostname: zoo3
????ports:
??????- 2183:2181
????environment:
??????ZOO_MY_ID: 3
??????ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=0.0.0.0:2888:3888;2181連接 ZooKeeper
將集群?jiǎn)?dòng)起來以后我們可以連接 ZooKeeper 對(duì)其進(jìn)行節(jié)點(diǎn)的相關(guān)操作。
首先需要下載 ZooKeeper。 將其解壓。 進(jìn)入其 conf/ 目錄,將 zoo_sample .cfg 改成 zoo.cfg。
#?The number of milliseconds of each tick
#?tickTime:CS通信心跳數(shù)
#?Zookeeper 服務(wù)器之間或客戶端與服務(wù)器之間維持心跳的時(shí)間間隔,也就是每個(gè) tickTime 時(shí)間就會(huì)發(fā)送一個(gè)心跳。tickTime以毫秒為單位。
tickTime=2000
#?The number of ticks that the initial
#?synchronization phase can take
#?initLimit:LF初始通信時(shí)限
#?集群中的follower服務(wù)器(F)與leader服務(wù)器(L)之間初始連接時(shí)能容忍的最多心跳數(shù)(tickTime的數(shù)量)。
initLimit=5
#?The number of ticks that can pass between
#?sending a request and getting an acknowledgement
#?syncLimit:LF同步通信時(shí)限
#?集群中的follower服務(wù)器與leader服務(wù)器之間請(qǐng)求和應(yīng)答之間能容忍的最多心跳數(shù)(tickTime的數(shù)量)。
syncLimit=2
#?the directory?where?the snapshot is stored.
#?do?not use /tmp?for?storage, /tmp here is just
#?example sakes.
#?dataDir:數(shù)據(jù)文件目錄
#?Zookeeper保存數(shù)據(jù)的目錄,默認(rèn)情況下,Zookeeper將寫數(shù)據(jù)的日志文件也保存在這個(gè)目錄里。
dataDir=/data/soft/zookeeper-3.4.12/data
#?dataLogDir:日志文件目錄
#?Zookeeper保存日志文件的目錄。
dataLogDir=/data/soft/zookeeper-3.4.12/logs
#?the port at?which?the clients will connect
#?clientPort:客戶端連接端口
#?客戶端連接 Zookeeper 服務(wù)器的端口,Zookeeper 會(huì)監(jiān)聽這個(gè)端口,接受客戶端的訪問請(qǐng)求。
clientPort=2181
#?the maximum number of client connections.
#?increase this?if?you need to handle more clients
#maxClientCnxns=60
#
#?Be sure to?read?the maintenance section of the
#?administrator guide before turning on autopurge.
#
#?http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
#?The number of snapshots to retain?in?dataDir
#autopurge.snapRetainCount=3
#?Purge task interval?in?hours
#?Set to?"0"?to?disable?auto purge feature
#autopurge.purgeInterval=1
#?服務(wù)器名稱與地址:集群信息(服務(wù)器編號(hào),服務(wù)器地址,LF通信端口,選舉端口)
#?這個(gè)配置項(xiàng)的書寫格式比較特殊,規(guī)則如下:
#?server.N=YYY:A:B
#?其中N表示服務(wù)器編號(hào),YYY表示服務(wù)器的IP地址,A為L(zhǎng)F通信端口,表示該服務(wù)器與集群中的leader交換的信息的端口。B為選舉端口,表示選舉新leader時(shí)服務(wù)器間相互通信的端口(當(dāng)leader掛掉時(shí),其余服務(wù)器會(huì)相互通信,選擇出新的leader)。一般來說,集群中每個(gè)服務(wù)器的A端口都是一樣,每個(gè)服務(wù)器的B端口也是一樣。但是當(dāng)所采用的為偽集群時(shí),IP地址都一樣,只能時(shí)A端口和B端口不一樣。可以不修改 zoo.cfg,使用默認(rèn)配置。接下來在解壓后的 bin/ 目錄中執(zhí)行命令?./zkCli.sh -server 127.0.0.1:2181?就能進(jìn)行連接了。
Welcome?to?ZooKeeper!
2020-06-01?15:03:52,512?[myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1025] - Opening socket connection?to?server localhost/127.0.0.1:2181. Will not attempt?to?authenticate using SASL (unknown error)
JLine support?is?enabled
2020-06-01?15:03:52,576?[myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@879] - Socket connection established?to?localhost/127.0.0.1:2181, initiating session
2020-06-01?15:03:52,599?[myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1299] - Session establishment?complete?on?server localhost/127.0.0.1:2181, sessionid =?0x100001140080000, negotiated timeout =?30000
WATCHER::
WatchedEvent state:SyncConnected?type:None path:null
[zk:?127.0.0.1:2181(CONNECTED)?0]使用 ls 命令查看當(dāng)前 ZooKeeper 中所包含的內(nèi)容。命令:ls /
[zk:?127.0.0.1:2181(CONNECTED)?10]?ls?/創(chuàng)建了一個(gè)新的 znode 節(jié)點(diǎn)?zk?以及與它關(guān)聯(lián)的字符串。命令:create /zk myData
[zk: 127.0.0.1:2181(CONNECTED) 11]?create?/zk myDataCreated /zk
[zk: 127.0.0.1:2181(CONNECTED) 12] ls /
[zk, zookeeper]
[zk: 127.0.0.1:2181(CONNECTED) 13]
獲取 znode 節(jié)點(diǎn) zk。命令:get /zk
[zk: 127.0.0.1:2181(CONNECTED) 13]?get?/zk
myData
cZxid =?0x400000008
ctime = Mon Jun?01?15:07:50?CST?2020
mZxid =?0x400000008
mtime = Mon Jun?01?15:07:50?CST?2020
pZxid =?0x400000008
cversion =?0
dataVersion =?0
aclVersion =?0
ephemeralOwner =?0x0
dataLength =?6
numChildren =?0刪除 znode 節(jié)點(diǎn) zk。命令:delete /zk
[zk: 127.0.0.1:2181(CONNECTED) 14] delete /zk
[zk: 127.0.0.1:2181(CONNECTED) 15] ls /
[zookeeper]由于篇幅有限,在接下來的文章中會(huì)根據(jù)上面提到的 ZooKeeper 應(yīng)用場(chǎng)景逐一進(jìn)行用代碼進(jìn)行實(shí)現(xiàn)。
大家可以直接從 GitHub 拉取項(xiàng)目,啟動(dòng)只需要兩步:
從 GitHub 上面拉取項(xiàng)目。 在 ZooKeeper 文件夾中執(zhí)行?docker-compose up?命令。
GitHub:github.com/modouxiansheng/about-docker/tree/master/ZooKeeper
來源:jianshu.com/p/6d349acf48aa
版權(quán)申明:內(nèi)容來源網(wǎng)絡(luò),版權(quán)歸原創(chuàng)者所有。除非無法確認(rèn),我們都會(huì)標(biāo)明作者及出處,如有侵權(quán)煩請(qǐng)告知,我們會(huì)立即刪除并表示歉意。謝謝!

