跳到主要内容

集群部署

Zookeeper为了更好的实现生产的业务场景,一般都会采用分布式的集群架构。集群通常由2n+1台Server节点组成,每个Server都知道彼此的存在。每个server都维护的内存状态镜像以及持久化存储的事务日志和快照。

对于2n+1台server,只要有>=(n+1)台server节点可用,整个Zookeeper系统保持可用。

为了维护集群内部所有主机信息的一致性,他们自己参考Paxos协议自己设计了一个更加轻量级的协议:Zab(Zookeeper Atomic Broadcast)来解决集群数据一致性的问题。

这个协议主要包括两部分:领导选举、日常通信,这两步就组成了Zookeeper的集群流程。

1111

222

集群流程

集群流程主要包括两阶段组成:Leader选举和日常操作。

Leader选举阶段: Leader选举主要有两种场景:集群启动、Leader恢复。

集群启动:当Zookeeper集群启动时候,将会选择一台server节点为为Leader,其它的server节点 就作为follower(暂不考虑observer),接着就进入日常操作阶段。

Leader恢复:当集群Leader主机服务重启或者崩溃后,当Zookeeper集群中所有Server主机基于 Zab协议选举新的Leader者,接着就进入日常操作阶段。然后其他Server主机和新的Leader主机进行数据 信息同步,当状态同步完成以后, 日常操作阶段: 日常操作阶段主要有两种场景:主机间心跳监测和数据操作。

主机间心跳监测: 当Leader选举完毕后,就进入日常操作阶段,第一步就是所有集群节点都互相保持通信, 然后Leader和Follower节点间进行数据同步,确保所有主机节点都是相同的状态, 当所有Follower节点和新的Leader主机完成数据信息同步以后,就开始进行日常的数据操作。

数据操作: follower来接收client的请求,对于不改变系统一致性状态的读操作, 由follower的本地内存数据库直接给client返回结果;对于会改变Zookeeper系统状态的更新 操作, 则转交由Leader进行提议处理,处理完毕后,将成功的结果给client。

通信机制

对于Zookeeper集群来说,我们要考虑的内容主要有三大块:客户端连接、主机通信、选举Leader。

客户端连接: 客户端连接服务端功能,进行相关请求操作 主机通信: 集群各服务节点进行信息交流的功能 选举Leader: 集群中各服务节点共同选举主节点的功能

格式

server.<myid>=<server_ip>:<LF_Port>:<L_Port>

为了同时满足这三者的要求,Zookeeper分别将这三种功能以三个常见端口对外提供服务:

  • 客户端操作: 2181

  • 主机通信: 2182

  • 选举Leader: 2183

注意: 这三端口都是自定义的,在生产中,因为每台主机都有独立的ip,所以三个端口一般都设置一样。

集群部署

Zookeeper集群使用多个独立的主机,每个主机上都部署同样环境的Zookeeper环境,基于内部的Zab协议达到数据的一致性,然后统一对外提供服务。客户端连接任意一节点,效果都一样。

节点主机IP通信端口心跳端口选举端口软件存放目录myid
zk1192.168.10.126218121822183/data/server/zk1/{data,logs}1
zk2192.168.10.127218121822183/data/server/zk2/{data,logs}2
zk3192.168.10.128218121822183/data/server/zk3/{data,logs}3

软件安装

分别在三个不同的Zookeeper目录中执行软件安装 安装三个节点

tar xf /data/softs/apache-zookeeper-3.7.0.tar.gz -C /data/server/
mv /data/server/apache-zookeeper-3.7.0 /data/server/zk1
mkdir /data/softs/zk/{data,log} -p

注意: 三个节点执行同样的操作,唯一的区别是数字不一致,分别是1-2-3

配置管理

准备配置文件
cd /data/server/
mv zk1/conf/zoo_sample.cfg zk1/conf/zoo.cfg

修改配置文件
# grep -ni '^[a-Z]' zk1/conf/zoo.cfg
2:tickTime=2000
5:initLimit=10
8:syncLimit=5
12:dataDir=/data/server/zk1/data
13:dataLogDir=/data/server/zk1/log
15:clientPort=2181
30:server.1=192.168.10.126:2182:2183
31:server.2=192.168.10.127:2282:2283
32:server.3=192.168.10.128:2382:2383

设置myid文件
echo 1 > zk1/data/myid

注意:
三个节点执行同样的操作,唯一的区别是绿色背景的字体不一致,分别是1-2-3

启动服务

以上三个节点内容都配置完毕后,我们就可以启动集群了。

与单机模式的启动方法一致,只需一次启动所有Zookeeper节点即可启动整个集群。我们还可以一个一
个的手工启动,当然了我们还可以使用脚本方式一次启动所有Zookeeper主机服务。
启动服务
/data/server/zk1/bin/zkServer.sh start
/data/server/zk2/bin/zkServer.sh start
/data/server/zk3/bin/zkServer.sh start

服务启动停止脚本

#!/bin/bash 
case $1 in
"start"){
for i in zk1 zk2 zk3
do
echo ---------- zookeeper $i 启动 ------------
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh start"
done
};;
"stop"){
for i in zk1 zk2 zk3
do
echo ---------- zookeeper $i 停止 ------------
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh stop"
done
};;
"status"){
for i in zk1 zk2 zk3
do
echo ---------- zookeeper $i 状态 ------------
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh status"
done
};;
esac

#增加脚本执行权限
$ chmod u+x zk.sh
#执行 Zookeeper 集群启动脚本
$ zk.sh start
Zookeeper 集群停止脚本
$ zk.sh stop

服务检查

检查集群服务一般有两类方法:检查端口和检查集群服务状态

检查端口
netstat -tnulp | grep 218


查看集群服务状态
[root@controller ~]# /data/server/zk1/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /data/server/zk1/bin/../conf/zoo.cfg
Mode: follower

[root@controller ~]# /data/server/zk2/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /data/server/zk2/bin/../conf/zoo.cfg
Mode: leader


[root@controller ~]# /data/server/zk3/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /data/server/zk3/bin/../conf/zoo.cfg
Mode: follower

结果显示:
查看集群状态,关键就是看Mode:的值,我们可以看到,目前Zookeeper三节点集群中,处于leader的
是zk2节点,其他两个节点是follower角色。
同时连接多个server的方法
bin/zkCli -server <zk1_ip>:<zk1_port>,<zk2_ip>:<zk2_port>,<zk3_ip>:<zk3_port>

注意:
同时连接多个server节点的时候,彼此间使用逗号隔开
使用任意一个zkCli.sh连接三个Zookeeper节点
cd /data/server/zk2/bin/
./zkCli.sh -server 192.168.10.126:2181,192.168.10.127:2281,192.168.10.128:2381

专用检测

因为使用telnet方法来检查集群的节点状态信息比较繁琐,而且经常中断,所以生产中我们一般使用nc软件 来检查Zookeeper集群状态.

nc全称NetCat,在网络工具中有“瑞士军刀”美誉,支持Windows和Linux。因为它短小精悍(不过25k)、功 能实用,被设计为一个简单、可靠的网络工具,可通过TCP或UDP协议传输读写数据。同时,它还是一个网络应用Debug分析器,因为它可以根据需要创建各种不同类型的网络连接。

安装软件
apt-get -y install netcat-traditional
使用方式
echo "命令" | nc <server_ip> <server_port>
检查集群状态
echo stat | nc 192.168.10.126 2181
echo stat | nc 192.168.10.127 2281
echo stat | nc 192.168.10.128 2381

集群操作命令

常见命令

命令内容
conf输出相关服务配置的详细信息
cons列出所有连接到服务器的客户端的完全的连接/会话的详细信息
envi输出关于服务环境的详细信息
dump列出未经处理的会话和临时节点
stat查看哪个节点被选择作为 Follower 或者 Leader
ruok测试是否启动了该 Server,若回复 imok 表示已经启动
mntr输出一些运行时信息
reqs列出未经处理的请求
wchs列出服务器 watch 的简要信息
wchc通过 session 列出服务器 watch 的详细信息
wchp通过路径列出服务器 watch 的详细信息
srvr输出服务的所有信息
srst重置服务器统计信息
kill关掉 Server
isro查看该服务的节点权限信息

ZooKeeper 支持某些特定的四字命令字母与其的交互。它们大多是查询命令,用来获取 ZooKeeper 服务的当前状态及相关信息。用户在客户端可以通过 telnet 或 nc 向 ZooKeeper 提交相应的命令。 默认情况下,这些4字命令有可能会被拒绝,发送如下报错 xxx is not executed because it is not in the whitelist. 解决办法:向 zoo.cfg 文件中添加如下配置 4lw.commands.whitelist=*

命令实践

查看节点服务状态
echo stat | nc 127.0.0.1 2281

查看节点服务配置
echo conf | nc 127.0.0.1 2281

查看节点服务环境
echo envi | nc 127.0.0.1 2281

查看节点服务会话
echo cons | nc 127.0.0.1 2281
echo dump | nc 127.0.0.1 2281

基本安全

在这么多的服务状态查看命令中有很多存在隐患的命令,所以为了避免生产中因为这些命令的安全隐患,所以
我们要对这些命令进行一些安全限制,只需要编辑服务的zoo.cfg文件即可

# vim /data/server/zk1/conf/zoo.cfg
4lw.commands.whitelist=stat, ruok, conf, isro

重启服务后
/data/server/zk1/bin/zkServer.sh restart
查看允许通过的命令效果
echo isro | nc 127.0.0.1 2181
echo conf | nc 127.0.0.1 2181
echo stat | nc 127.0.0.1 2181

检查不允许通过的命令
[root@controller bin]# echo dump | nc 127.0.0.1 2181
dump is not executed because it is not in the whitelist.

测试没有设置命令过滤的节点
[root@controller bin]# echo dump | nc 127.0.0.1 2281
SessionTracker dump:
Session Sets (0):
ephemeral nodes dump:
Sessions with Ephemerals (0):
所以生产中,我们一定要把不知道或者不想用的命令全部过滤掉,这样才能保证基本的安全。

集群管理

状态监控

在Zookeeper服务端的操作中,有一个命令非常有用就是mntr,可以查看节点服务的所有运行时信息,这些 信息就是我们平常要监控到的内容。

命令效果
# echo mntr | nc 127.0.0.1 2281
zk_version 3.7.0-39d3a4f269333c922ed3db283be479f9deacaa0f, built on 03/23/2021
10:13 GMT
zk_avg_latency 0
zk_max_latency 0
zk_min_latency 0
zk_packets_received 8
zk_packets_sent 7
zk_num_alive_connections 1
zk_outstanding_requests 0
zk_server_state leader
zk_znode_count 4
zk_watch_count 0
zk_ephemerals_count 0
zk_approximate_data_size 27
zk_open_file_descriptor_count 36
zk_max_file_descriptor_count 4096
zk_followers 2
zk_synced_followers 2
zk_pending_syncs 0

指标分类

网络响应延迟信息
zk_avg_latency、zk_max_latency、zk_min_latency

网络请求(数据包和连接状态数量)

数据包相关:zk_packets_received、zk_packets_sent
连接状态相关:zk_num_alive_connections(活跃连接)、zk_outstanding_requests

节点数量信息:
zk_znode_count、zk_watch_count、zk_ephemerals_count(临时节点数)

服务状态
zk_server_state、zk_open_file_descriptor_count、zk_max_file_descriptor_count

Leader特有:
zk_followers、zk_synced_followers(同步数量)、zk_pending_syncs(阻塞数量)

集群优化

文件隔离
生产中Zookeeper的dataDir 和 dataLogDir 应该分开部署,因为事务日志非常重要而且内容比较多,
所以在配置的时候,dataLogDir所在的目录,要保证目录空间足够大,并挂载到单独的磁盘上,如果可以的
话,磁盘应该开启实时刷新功能。
日志滚动
默认情况下,一般日志是放在一个文件中,为了更好的查看日志效果,我们一般会将日志进行切割,接下来我
们配置一下日志的切割功能。

Zookeeper的默认日志切割配置文件是 项目目录的conf/log4j.properties,和切割配置主要相关的是:
log4j.appender.ROLLINGFILE=org.apache.log4j.RollingFileAppender
如果想按天进行日志切割的话,可以修改为 DaliyRollingFileAppender


Zookeeper使用日志切割功能
# vim /data/server/zk1/bin/zkServer.sh
...
30 # 增加 ZOO_LOG_DIR 配置
31 ZOO_LOG_DIR="$ZOOBINDIR/../log4j"
...
# vim /data/server/zk1/bin/zkEnv.sh
59 if [ "x${ZOO_LOG4J_PROP}" = "x" ]
60 then
61 ZOO_LOG4J_PROP="INFO,ROLLINGFILE" # 注意:原CONSOLE 修改为
ROLLINGFILE
62 fi
日志清理
自动清理:自从Zookeeper 3.4.0版本之后,配置文件中多了两个和日志自动清理相关的配置
autopurge.purgeInterval:指定清理频率,单位为小时(默认是0,表示不开启自动清理)
autopurge.snapRetainCount:和purgeInterval配合使用,指定需要保留的文件数目

注意:
Zookeeper 重启会自动清除 zookeeper-root-server-python-auto.out 日志,如果有排错需要,则应先备份好日志文件


配置效果:
# vim /data/server/zk1/conf/zoo.cfg
...
autopurge.purgeInterval=1
autopurge.snapRetainCount=3

手工清理:
如果发现单事务日志量过大,导致定时清理无法及时处理,我们可以基于自定义脚本或者 zookeeper提供的 zkCleanup.sh 进行 结合 定时任务来实现自动清理的任务。


#!/bin/bash
# 定制日志目录
zookeeperDir='/data/server/zookeeper'
dataDir="$zookeeperDir/data/version-2"
dataLogDir=$zookeeperDir/logs/version-2

# 保留文件60
count=60
count=$[$count+1] # 从61行开始删除
ls -t $dataLogDir/log.* | tail -n +$count | xargs rm -f
ls -t $dataDir/snapshot.* | tail -n +$count | xargs rm -f

注意:
ls -t 是顺序排列,
tail -n +5 是从第 5 个至最新文件
节点扩展
在Zookeeper集群中有一个角色是observer,它主要的作用仅仅是增加额外的接收客户端请求的扩展
节点,将接收到的请求,转交给Leader处理,不会影响集群的其他任何操作。
我们只需要在Observe节点的zoo.cfg配置文件中添加如下配置即可

peerType=observer
server.n:localhost:2181:3181:observer

修改配置文件
Zk1节点:
vim /data/server/zk1/conf/zoo.cfg
# 修改如下配置
server.3=192.168.8.14:2382:2383:observer
Zk2节点:
vim /data/server/zk2/conf/zoo.cfg
# 修改如下配置
server.3=192.168.8.14:2382:2383:observer
Zk3节点:
vim /data/server/zk3/conf/zoo.cfg
# 增加如下配置
peerType=observer
# 修改如下配置
server.3=192.168.8.14:2382:2383:observer
重启相关服务
/data/server/zk1/bin/zkServer.sh restart
/data/server/zk2/bin/zkServer.sh restart
/data/server/zk3/bin/zkServer.sh restart

再次查看集群状态
/data/server/zk3/bin/zkServer.sh status
/data/server/zk2/bin/zkServer.sh status
/data/server/zk1/bin/zkServer.sh status
可以看到:
zk3的集群角色就变成了观察者
验证observer是否参与选举
/data/server/zk2/bin/zkServer.sh stop
查看集群状态
/data/server/zk1/bin/zkServer.sh status
可以看到:
集群节点有三个,zk3是观察者,真正提供服务的是两个,我们关闭了一个,集群服务就崩溃了,所以
observer没 有参与集群的选举工作。