ZooKeeper 原理與伺服器集群部署

2019-07-30     IT技術分享

ZooKeeper 是大型分布式系統中可靠的協調系統,它以樹狀結構存儲數據,以領導選舉和信息同步機制保證了集群的高可用性,以事件通知機制協助事件訂閱者及時捕獲數據的變化,可協助實現 Dubbo、Kafka 等架構。本文以 CentOS 和 Windows 為例,總結了 ZooKeeper 集群的部署操作,並以自帶的腳本命令操作其數據。

1.概述

ZooKeeper 是 Hadoop 的一個子項目,是大型分布式系統中可靠的協調系統。分布式應用程式以此實現更高級別的服務,可用於分布式系統的配置維護、名字服務、分布式同步、組服務等:

用於 Dubbo: 作為配置中心;

用於 Kafka: 作為 Broker/Producer/Consumer 共享的配置中心。

官網首頁: https://zookeeper.apache.org/

官網文檔: https://zookeeper.apache.org/doc/current/

1.1 ZAB協議

集群間通過 ZAB(ZooKeeper Atomic Broadcast)協議保持數據一致性,該協議包括兩個階段:

1.1.1 領導選舉(Leader Election)

選舉出一個 Leader(所有寫操作傳送給 Leader),其他機器被稱為 Follower;

當前 Leader 崩潰或失去大多數 Follower 後,會選舉出新的 Leader;

1.1.2 信息同步(Atomic broadcast)

用於同步 Leader 與 Follower 之間的信息,保證數據一致。

1.2 內部原理

https://zookeeper.apache.org/doc/current/zookeeperOver.html

存儲方式與標準文件系統非常相似,每個節點稱作 znode,本身包含數據,還可以擁有子節點。

客戶端以TCP連接一台節點,該節點故障時,客戶端會切換至其他節點。

客戶端可以訂閱某些節點的事件(watcher機制),當節點內容或其子節點有變化時,客戶端會收到通知。

  • 高性能:多讀少寫的情況下,速度很快;存儲於內存中,並有持久存儲中的事務日誌和快照;
  • 高可用性(無中心化結構可避免單點故障): 個別節點故障不影響整體使用;
  • 監視機制: 客戶端可以監視一個結點(node),當結點斷開或有修改時,客戶端會收到通知;
  • 順序一致性: 來自客戶端的更新將按照它們發送的順序進行應用。
  • 原子性: 保證數據完整、一致,更新成功或失敗,沒有部分結果。
  • 單系統映像: 無論伺服器連接到哪個伺服器,客戶端都會看到相同的服務視圖。
  • 可靠性: 一旦更新被應用,它將一直持續到客戶覆蓋更新。
  • 及時性: 系統的客戶觀點在一定的時間範圍內保證是最新的。

1.3 系統要求

ZooKeeper 以 Java 版本運行,Java 版本要求為 1.6+;

支持的作業系統包括: 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 設置環境變量

## sudo vim /etc/profile ## 所有用戶有效 
export ZOOKEEPER_HOME=/opt/zookeeper-3.4.11
export PATH=$PATH:$ZOOKEEPER_HOME/bin

文件保存後,Linux用戶重新登錄後生效。

2.3 準備目錄與配置文件

# 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 ## 數據目錄(存儲內存資料庫快照)
dataLogDir=$ZOOKEEPER_HOME/logs/$INDEX ## 日誌目錄(存儲事務日誌)
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): 「必須」是一個數字(表示這是第幾號server),否則報錯 java.lang.NumberFormatException: For input string: "xxx"
  • hostname(localhost): 是該 server 所在的域名或IP位址,為了通用,可替換為域名zk{n}.company.com 並在 hosts 里配置;
  • port1(2281,2282,2283): 當前 server 是 leader 時,監聽此埠接受 followers 的連接,注意followers不會監聽此埠(直到它升級為 leader)
  • port2(2291,2292,2293): 是選舉 leader 時所使用的埠。

必須生成文件 $ZOOKEEPER_HOME/data/%n/myid,其內容為 zoo.cnf 中的 N(伺服器ID), 否則拋出異常 java.lang.IllegalArgumentException: $ZOOKEEPER_HOME/data/{n}/myid file is missing

2.4 服務的配置並啟動

## sudo vim /usr/lib/systemd/system/[email protected] 
## 其中的 %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 防火牆放行

如果非本機應用需要連接 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 ## 進入命令行狀態 
help ## 顯示所有命令格式
quit ## 退出命令行狀態
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 清空數據【慎用】

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 卸載服務【慎用】

sudo systemctl stop zookeeper@{1,2,3} 
sudo systemctl disable zookeeper@{1,2,3}
sudo rm -rf $ZOOKEEPER_HOME

3.Windows 下安裝(可用於開發)

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 修改系統環境變量

set ZOOKEEPER_HOME={???}\\zookeeper-3.4.11 
set PATH=%ZOOKEEPER_HOME%\\bin

3.2.3 修改 conf\\zoo-%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\\%n\\myid
for %n in (1,2,3) do @copy/b conf\\zoo_sample.cfg conf\\zoo-%n.cfg

修改文件 conf\\zoo-%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

參數說明與 Linux 中相關內容一樣。

3.2.4 修改腳本

刪除 bin\\zkEnv.cmd 中的 set ZOOCFG=%ZOOCFGDIR%\\zoo.cfg 一行;

for %n in (1,2,3) do @copy/b bin\\zkServer.cmd bin\\zkServer%n.cmd 

修改各個文件 zkServer%n.cmd 在 call "%~dp0zkEnv.cmd" 之前加一行:

set ZOOCFG=%~dp0%..\\conf\\zoo-%n.cfg,注意替換 %n 分別為 1/2/3

3.3 啟動服務

zkServer1.cmd 
zkServer2.cmd
zkServer3.cmd

3.4 客戶端驗證

zkCli.cmd -server centos:2181 ## 連接 Linux 上服務 
zkCli.cmd -server localhost:2181 ## 連接本機上服務
## 更多內容參見前面 Linux 中相應部分

4.集群部署(生產環境)

管理員指南: https://zookeeper.apache.org/doc/current/zookeeperAdmin.html

  • 要求至少為三台 ZooKeeper 伺服器,最好是奇數個伺服器(以便多數正常機器處理少數機器的故障),通常三台足夠了,如果想更可靠,可增加至五台;
  • 為避免各伺服器同時發生故障,最好部署在不同機器、不同網絡交換機(電路、冷卻系統等)、甚至不同機房;
  • 為避免內存交換,要設置足夠大的 JVM 堆,比如 4G 機器可指定 3G;
文章來源: https://twgreatdaily.com/zh/NdZOzmwBJleJMoPMnTOu.html