ZooKeeper 是大型分布式系统中可靠的协调系统,它以树状结构存储数据,以领导选举和信息同步机制保证了集群的高可用性,以事件通知机制协助事件订阅者及时捕获数据的变化,可协助实现 Dubbo、Kafka 等架构。本文以 CentOS 和 Windows 为例,总结了 ZooKeeper 集群的部署操作,并以自带的脚本命令操作其数据。
ZooKeeper 是 Hadoop 的一个子项目,是大型分布式系统中可靠的协调系统。分布式应用程序以此实现更高级别的服务,可用于分布式系统的配置维护、名字服务、分布式同步、组服务等:
官网首页: https://zookeeper.apache.org/ 官网文档: https://zookeeper.apache.org/doc/current/
集群间通过 ZAB(ZooKeeper Atomic Broadcast)协议保持数据一致性,该协议包括两个阶段:
用于同步 Leader 与 Follower 之间的信息,保证数据一致。
https://zookeeper.apache.org/doc/current/zookeeperOver.html 存储方式与标准文件系统非常相似,每个节点称作 znode,本身包含数据,还可以拥有子节点。 客户端以TCP连接一台节点,该节点故障时,客户端会切换至其他节点。 客户端可以订阅某些节点的事件(watcher机制),当节点内容或其子节点有变化时,客户端会收到通知。
ZooKeeper 以 Java 版本运行,Java 版本要求为 1.6+; 支持的操作系统包括: GNU/Linux, Solaris, FreeBSD, Windows。
https://zookeeper.apache.org/doc/current/zookeeperStarted.html
# 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
## sudo vim /etc/profile ## 所有用户有效
export ZOOKEEPER_HOME=/opt/zookeeper-3.4.11
export PATH=$PATH:$ZOOKEEPER_HOME/bin
文件保存后,Linux用户重新登录后生效。
# 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
## 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}
如果非本机应用需要连接 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
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 /
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}
sudo systemctl stop zookeeper@{1,2,3}
sudo systemctl disable zookeeper@{1,2,3}
sudo rm -rf $ZOOKEEPER_HOME
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
set ZOOKEEPER_HOME={???}\zookeeper-3.4.11
set PATH=%ZOOKEEPER_HOME%\bin
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 中相关内容一样。
删除 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
zkServer1.cmd
zkServer2.cmd
zkServer3.cmd
zkCli.cmd -server centos:2181 ## 连接 Linux 上服务
zkCli.cmd -server localhost:2181 ## 连接本机上服务
## 更多内容参见前面 Linux 中相应部分
管理员指南: https://zookeeper.apache.org/doc/current/zookeeperAdmin.html
作者:王克锋
出处:https://kefeng.wang/2017/11/08/zookeeper-deploy/