ZooKeeper 是大型分布式系統(tǒng)中可靠的協(xié)調(diào)系統(tǒng),它以樹狀結(jié)構(gòu)存儲數(shù)據(jù),以領(lǐng)導(dǎo)選舉和信息同步機制保證了集群的高可用性,以事件通知機制協(xié)助事件訂閱者及時捕獲數(shù)據(jù)的變化,可協(xié)助實現(xiàn) Dubbo、Kafka 等架構(gòu)。本文以 centos 和 windows 為例,總結(jié)了 ZooKeeper 集群的部署操作,并以自帶的腳本命令操作其數(shù)據(jù)。
1.概述
ZooKeeper 是 Hadoop 的一個子項目,是大型分布式系統(tǒng)中可靠的協(xié)調(diào)系統(tǒng)。分布式應(yīng)用程序以此實現(xiàn)更高級別的服務(wù),可用于分布式系統(tǒng)的配置維護、名字服務(wù)、分布式同步、組服務(wù)等:
用于 Dubbo: 作為配置中心;
用于 Kafka: 作為 Broker/Producer/Consumer 共享的配置中心。
官網(wǎng)首頁: https://zookeeper.Apache.org/
官網(wǎng)文檔: https://zookeeper.apache.org/doc/current/
1.1 ZAB協(xié)議
集群間通過 ZAB(ZooKeeper Atomic Broadcast)協(xié)議保持數(shù)據(jù)一致性,該協(xié)議包括兩個階段:
1.1.1 領(lǐng)導(dǎo)選舉(Leader Election)
選舉出一個 Leader(所有寫操作傳送給 Leader),其他機器被稱為 Follower;
當(dāng)前 Leader 崩潰或失去大多數(shù) Follower 后,會選舉出新的 Leader;
1.1.2 信息同步(Atomic broadcast)
用于同步 Leader 與 Follower 之間的信息,保證數(shù)據(jù)一致。
1.2 內(nèi)部原理
https://zookeeper.apache.org/doc/current/zookeeperOver.html
存儲方式與標(biāo)準(zhǔn)文件系統(tǒng)非常相似,每個節(jié)點稱作 znode,本身包含數(shù)據(jù),還可以擁有子節(jié)點。
客戶端以TCP連接一臺節(jié)點,該節(jié)點故障時,客戶端會切換至其他節(jié)點。
客戶端可以訂閱某些節(jié)點的事件(watcher機制),當(dāng)節(jié)點內(nèi)容或其子節(jié)點有變化時,客戶端會收到通知。
- 高性能:多讀少寫的情況下,速度很快;存儲于內(nèi)存中,并有持久存儲中的事務(wù)日志和快照;
- 高可用性(無中心化結(jié)構(gòu)可避免單點故障): 個別節(jié)點故障不影響整體使用;
- 監(jiān)視機制: 客戶端可以監(jiān)視一個結(jié)點(node),當(dāng)結(jié)點斷開或有修改時,客戶端會收到通知;
- 順序一致性: 來自客戶端的更新將按照它們發(fā)送的順序進行應(yīng)用。
- 原子性: 保證數(shù)據(jù)完整、一致,更新成功或失敗,沒有部分結(jié)果。
- 單系統(tǒng)映像: 無論服務(wù)器連接到哪個服務(wù)器,客戶端都會看到相同的服務(wù)視圖。
- 可靠性: 一旦更新被應(yīng)用,它將一直持續(xù)到客戶覆蓋更新。
- 及時性: 系統(tǒng)的客戶觀點在一定的時間范圍內(nèi)保證是最新的。
1.3 系統(tǒng)要求
ZooKeeper 以 JAVA 版本運行,Java 版本要求為 1.6+;
支持的操作系統(tǒng)包括: GNU/linux, Solaris, FreeBSD, Windows。
2.Linux 下安裝
https://zookeeper.apache.org/doc/current/zookeeperStarted.html
2.1 下載并解壓(35M)
# https://archive.apache.org/dist/zookeeper/ # https://archive.apache.org/dist/zookeeper/zookeeper-3.4.11/ wget https://archive.apache.org/dist/zookeeper/zookeeper-3.4.11/zookeeper-3.4.11.tar.gz sudo rm -rf /opt/zookeeper-3.4.11 sudo tar -zxf zookeeper-3.4.11.tar.gz -C /opt sudo chown -R root:root /opt/zookeeper-3.4.11 sudo rm -rf /opt/zookeeper-3.4.11/bin/*.cmd
2.2 設(shè)置環(huán)境變量
## sudo vim /etc/profile ## 所有用戶有效 export ZOOKEEPER_HOME=/opt/zookeeper-3.4.11 export PATH=$PATH:$ZOOKEEPER_HOME/bin
文件保存后,Linux用戶重新登錄后生效。
2.3 準(zhǔn)備目錄與配置文件
# sudo vim $ZOOKEEPER_HOME/bin/zkInit.sh # sudo -E sh $ZOOKEEPER_HOME/bin/zkInit.sh for INDEX in {1..3}; do sudo rm -rf $ZOOKEEPER_HOME/{data,logs}/$INDEX sudo mkdir -p $ZOOKEEPER_HOME/{data,logs}/$INDEX echo $INDEX | sudo tee $ZOOKEEPER_HOME/data/$INDEX/myid > /dev/null # zoo.cfg 參考: grep -v "^#" $ZOOKEEPER_HOME/conf/zoo_sample.cfg cat > $ZOOKEEPER_HOME/conf/zoo-$INDEX.cfg << EOF tickTime=2000 ## ZooKeeper 的最小時間單位(ms) initLimit=10 ## 投票選舉新 leader 的初始化時間(以 tickTime 為單位) syncLimit=5 ## Leader 檢測 Follower 可用性心跳的超時時間(以 tickTime 為單位) clientPort=218$INDEX ## 客戶端用來連接 ZooKeeper 的端口 dataDir=$ZOOKEEPER_HOME/data/$INDEX ## 數(shù)據(jù)目錄(存儲內(nèi)存數(shù)據(jù)庫快照) dataLogDir=$ZOOKEEPER_HOME/logs/$INDEX ## 日志目錄(存儲事務(wù)日志) server.1=localhost:2281:2291 server.2=localhost:2282:2292 server.3=localhost:2283:2293 EOF done
其中的 clientPort=218$INDEX 是提供給客戶端連接的端口(2181,2182,2183);
其中的 server.N = hostname : port1 : port2:
- N(1,2,3): “必須”是一個數(shù)字(表示這是第幾號server),否則報錯 java.lang.NumberFormatException: For input string: "xxx"
- hostname(localhost): 是該 server 所在的域名或IP地址,為了通用,可替換為域名zk{n}.company.com 并在 hosts 里配置;
- port1(2281,2282,2283): 當(dāng)前 server 是 leader 時,監(jiān)聽此端口接受 followers 的連接,注意followers不會監(jiān)聽此端口(直到它升級為 leader)
- port2(2291,2292,2293): 是選舉 leader 時所使用的端口。
必須生成文件 $ZOOKEEPER_HOME/data/%n/myid,其內(nèi)容為 zoo.cnf 中的 N(服務(wù)器ID), 否則拋出異常 java.lang.IllegalArgumentException: $ZOOKEEPER_HOME/data/{n}/myid file is missing
2.4 服務(wù)的配置并啟動
## sudo vim /usr/lib/systemd/system/zookeeper@.service ## 其中的 %i 將來會被替換為具體的 1/2/3 [Unit] Description=ZooKeeper After=syslog.target network.target [Service] Type=forking Environment="ZOOCFG=zoo-%i.cfg" ExecStart=/opt/zookeeper-3.4.11/bin/zkServer.sh start ExecStop=/opt/zookeeper-3.4.11/bin/zkServer.sh stop [Install] WantedBy=multi-user.target
配置為自動啟動,并立即啟動:
sudo systemctl daemon-reload sudo systemctl enable zookeeper@{1,2,3} sudo systemctl start zookeeper@{1,2,3} sudo netstat -natp | grep LISTEN | grep -E "218|228|229" # sudo systemctl stop zookeeper@{1,2,3}
2.5 防火墻放行
如果非本機應(yīng)用需要連接 ZooKeeper,必須把所有 clientPort 端口放行。
### sudo vim /etc/sysconfig/iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 2181 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 2182 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 2183 -j ACCEPT ### 重啟生效: sudo systemctl restart iptables
2.6 客戶端驗證
zkCli.sh -server localhost:2181 ## 進入命令行狀態(tài) help ## 顯示所有命令格式 quit ## 退出命令行狀態(tài) history ## 顯示歷史命令 ls path [watch] createpath data acl delete path [version] set path data [version] get path [watch] stat path [watch] sync path listquota path setquota -n|-b val path delquota [-n|-b] path addauth scheme auth setAcl path acl getAcl path printwatches on|off redo cmdno
也可集連接和命令于一行:
zkCli.sh -server localhost:2181 ls /
2.7 清空數(shù)據(jù)【慎用】
sudo systemctl stop zookeeper@{1,2,3} sudo rm -rf $ZOOKEEPER_HOME/{logs,data}/{1,2,3}/version-* sudo systemctl start zookeeper@{1,2,3}
2.8 卸載服務(wù)【慎用】
sudo systemctl stop zookeeper@{1,2,3} sudo systemctl disable zookeeper@{1,2,3} sudo rm -rf $ZOOKEEPER_HOME
3.Windows 下安裝(可用于開發(fā))
3.1 下載
https://archive.apache.org/dist/zookeeper/
https://archive.apache.org/dist/zookeeper/zookeeper-3.4.11/
https://archive.apache.org/dist/zookeeper/zookeeper-3.4.11/zookeeper-3.4.11.tar.gz
3.2 安裝
3.2.1 解壓
3.2.2 修改系統(tǒng)環(huán)境變量
set ZOOKEEPER_HOME={???}zookeeper-3.4.11 set PATH=%ZOOKEEPER_HOME%bin
3.2.3 修改 confzoo-%n.cfg
cd/d %ZOOKEEPER_HOME% del /q bin*.sh rd/s/q data logs for %n in (1,2,3) do @mkdir logs%n for %n in (1,2,3) do @mkdir data%n for %n in (1,2,3) do @echo %n> data%nmyid for %n in (1,2,3) do @copy/b confzoo_sample.cfg confzoo-%n.cfg
修改文件 confzoo-%n.cfg 如下(分別替換其中的 %n 為 1,2,3):
tickTime=2000 initLimit=10 syncLimit=5 clientPort=218%n dataDir=D:/Software/Architecture/zookeeper-3.4.11/data/%n dataLogDir=D:/Software/Architecture/zookeeper-3.4.11/logs/%n server.1=localhost:2281:2291 server.2=localhost:2282:2292 server.3=localhost:2283:2293
參數(shù)說明與 Linux 中相關(guān)內(nèi)容一樣。
3.2.4 修改腳本
刪除 binzkEnv.cmd 中的 set ZOOCFG=%ZOOCFGDIR%zoo.cfg 一行;
for %n in (1,2,3) do @copy/b binzkServer.cmd binzkServer%n.cmd
修改各個文件 zkServer%n.cmd 在 call "%~dp0zkEnv.cmd" 之前加一行:
set ZOOCFG=%~dp0%..confzoo-%n.cfg,注意替換 %n 分別為 1/2/3
3.3 啟動服務(wù)
zkServer1.cmd zkServer2.cmd zkServer3.cmd
3.4 客戶端驗證
zkCli.cmd -server centos:2181 ## 連接 Linux 上服務(wù) zkCli.cmd -server localhost:2181 ## 連接本機上服務(wù) ## 更多內(nèi)容參見前面 Linux 中相應(yīng)部分
4.集群部署(生產(chǎn)環(huán)境)
管理員指南: https://zookeeper.apache.org/doc/current/zookeeperAdmin.html
- 要求至少為三臺 ZooKeeper 服務(wù)器,最好是奇數(shù)個服務(wù)器(以便多數(shù)正常機器處理少數(shù)機器的故障),通常三臺足夠了,如果想更可靠,可增加至五臺;
- 為避免各服務(wù)器同時發(fā)生故障,最好部署在不同機器、不同網(wǎng)絡(luò)交換機(電路、冷卻系統(tǒng)等)、甚至不同機房;
- 為避免內(nèi)存交換,要設(shè)置足夠大的 JVM 堆,比如 4G 機器可指定 3G;