2.大数据架构技术 中——搭建Zookeeper集群
大数据架构技术 中——搭建Zookeeper集群
文章目录
一、Zookeeper简述
Zookeeper是一个开源的分布式应用程序协调服务;用于维护配置信息、命名、提供分布式同步和提供组服务,对集群间的数据保证事务一致性,封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户
ZooKeeper本身不做业务计算或数据存储,它提供的是分布式环境下的协调能力。在Hadoop生态中,多个核心组件都依赖ZooKeeper来解决分布式场景下的关键问题包含选主、协调、锁、通知、配置,例如在HA高可用模式中解决hdfs的NN节点和yarn的RM节点在宕机时的主备切换,在其他大数据组件中作为神经中枢
二、Zookeeper角色与特性
Leader:作为Master节点负责读写操作,为客户端服务同时接受所有Follower的提案请求并同一协调发起提案的投票,负责与所有的Follower通信进行内部数据交换
Follower:作为slave节点负责提供读服务,直接为客户端服务收到写请求会转发给Leader,参与提案的投票但不参与提案的发起,参与Leader选举同时与Leader进行数据交换
Observer:作为slave节点负责提供读服务,直接为客户端服务收到写请求会转发给Leader,既不参与提案的投票也不参与提案的发起,不直接参与Leader选举但可以在非启动状态下被手动提拔为Follower节点参与投票,若在运行状态中需要在配置文件中声明并重启节点,同时与Leader进行数据交换,不过这种本质上已经算是重新部署角色了
注意:服务启动时没有角色,角色通过选举产生一个Leader,其余的为Follower和Observer节点;投票中只有同时得到半数以上节点票数才能当选Leader节点,而且是基于集群总节点数计算过半数的结果,而非当前剩余节点数,所以集群的投票节点数量建议保持基数;如果Leader节点下线会重新选举,但当节点数量不足一半时集群无法选举出新Leader导致服务不可用,因为剩余节点无法得到足够的投票数量,并非按照当前数量而是按照节点总数计算
三、ZooKeeper 重要概念概述
ZNode节点数据模型
ZooKeeper内部维护了一个树形结构系统也就是"命名空间"(Namespace),树上每个节点称为ZNode(ZooKeeper Node),每个ZNode都有一个唯一的路径标识。ZNode节点是协调分布式系统里的共享状态,具体执行是通过代码操作ZK集群管理分布式任务、节点扩缩容、回调函数监控节点变化,在工作流中应用代码调用ZKapi监听ZNode,由ZK集群通知并同步ZNode中记录的各个节点状态,应用代码执行业务逻辑
ZNode节点在从两个维度 持久 与 顺序,持久代表会话断开后节点在ZK的持久性保留直到被显式删除,而顺序是谁来分配任务序列号,当分布式任务编号由ZK有序分发序号保证全局唯一且单调递增即 顺序
两个维度组合成四种类型分别是
持久节点:最常用的类型,节点名由客户端自己指定并且创建后永久存在不会因断开而消失。主要用于任何需要持久化并且共享存储的任务
临时节点:节点随客户端会话存在而存在,会话断开即消失,心跳检测与在线状态感知
持久顺序节点:数据持久化并且任务序列号由ZK分发,保障序号全局唯一且单调递增同时多客户端并发创建不会冲突
临时顺序节点:不仅由于ZK自动分配唯一序号并且节点状态与会话状态相关,主用于分布式锁,抢锁时谁都创建 lock 节点但ZK分配序列号后谁的序号最小谁就持有锁
关于四种类型的更多具体细节描述参考站内大佬讲解
https://zuiyl.blog.csdn.net/article/details/158538058?fromshare=blogdetail&sharetype=blogdetail&sharerId=158538058&sharerefer=PC&sharesource=m0_69799942&sharefrom=from_link
ZNode节点在实际操作上既可以存数据也可以下分子节点也就是说不做目录与文件的区分,充当存储数据时存放的并非一些大文件而是与分布式节点有关的配置信息、状态标记等小量数据,充当目录时则不存储业务数据而是作为子节点的容器,通过路径层级来归类管理大量子节点,实现命名空间隔离、批量管理入口和子树级 Watch 监听
在ZNode节存储的信息中dataVersion(数据版本号)是一个重要的机制:每当修改数据时版本号自增。客户端可以利用版本号实现CAS(Compare And Swap)操作,只有当版本号匹配时才允许修改就能避免并发冲突,这是 ZooKeeper实现分布式锁的基础原理之一
Watch监听机制
watch监听机制时ZooKeeper核心特性之一,客户端关注的ZNode节点发生变更时ZooKeeper会主动通知客户端而不是让客户端不断轮询
watch工作流程如下
客户端A ZooKeeper 客户端B
| | |
|--- 读取 /config 并注册Watch --->| |
|<-- 返回数据并声明Watch注册成功 ---| |
| | |
| |<--- 修改 /config 的数据 ---|
| | |
|<-- Watch通知:/config已变更 ---| |
|--- 重新读取 /config --->| |
|<-- 返回新数据 ---| |
Watch是一次性的,触发一次后失效,需要重新注册
ZAB协议概述
ZAB(ZooKeeper Atomic Broadcast,ZooKeeper原子广播)协议是ZooKeeper用以实现多节点各自维护一份数据同时保证所有节点的数据一致性的核心协议。协议分为两个阶段:崩溃恢复阶段(选举Leader)和原子广播阶段(数据同步)
崩溃恢复(选举Leader):
这个阶段的核心任务是选举出一个新的Leader。当集群刚启动或者Leader宕机时进入崩溃恢复阶段,每个节点启动后,向其他节点发送投票信息包含myid和zxid(前者是节点编号,后者是节点最后处理的事务ID越大说明处理的数据事务越新),节点收到其他节点的信息在比较myid和zxid后投票(优先比较后者,zxid越大代表节点数据越新也就优先当选,当zxid相同时myid大的优先当选),当某个节点获得了超过半数投票它就成为Leader,等待确认后Follower与Leader进行数据同步确保所有节点的数据与Leader完全一致(将新Leader中已提交但Follower未提交的事务补齐),同步完成后集群进入正常状态
原子广播(正常工作):
集群选举完成、数据同步完毕后,进入原子广播阶段。这个阶段处理所有写请求,具体写操作流程如下:
客户端 Leader Follower1 Follower2
| | | |
|-------- 写请求 --------->| | |
| | | |
| |--- 提案(Proposal) ---->| |
| |--- 提案(Proposal) ----------------->|
| | | |
| |<-- 确认(Ack) ----------| |
| |<-- 确认(Ack) -----------------------|
| | | |
| [收到过半数确认,提交事务] | |
| | | |
| |--- 提交(Commit) ------>| |
| |--- 提交(Commit) --------------------|
|<------- 响应成功 ---------| | |
Proposal(提案):Leader将写操作以提案的形式广播给所有Follower
Ack(确认):Follower收到提案后回复确认
Commit(提交):当Leader收到超过半数Follower的确认后正式提交该事务并通知所有Follower
为什么ZAB协议只有写请求,而读操作不需要ZAB
读操作可以直接由Leader或任意Follower处理,不走广播流程。这是ZooKeeper读写性能差异较大的原因——写操作需要等待多数派确认(有网络开销),读操作直接返回本地数据(速度很快)。Observer 节点的存在就是为了在不增加写操作投票成本的前提下,提升集群的读性能
四、前置环境准备
系统规划
在上篇中,案例搭建了 Hadoop 3.4.3,为了兼容适配 ZooKeeper 选择 3.8.x 系列搭配,从官网下载 3.8.6 版本(当前最新 3.8.x 稳定版)的 tar 包
https://zookeeper.apache.org/releases.html
| 主机名 | 硬件性能 | 部署角色 | 组件服务 |
|---|---|---|---|
| 192.168.8.21 zk-f1 | 2C6G 20G | Follower | Zookeeper |
| 192.168.8.22 zk-f2 | 2C6G 20G | Follower | Zookeeper |
| 192.168.8.23 zk-f3 | 2C6G 20G | Follower | Zookeeper |
| 192.168.8.24 zk-o1 | 2C6G 20G | Observer | Zookeeper |
Zookeeper 集群准备环境复用上篇中的hadoop集群节点,包含node1-4总共四个节点,其中node4手动标记Observer节点,另外3台作为Follower节点在启动服务后会投票删选出Leader节点,案例复用节点主机名不做变动,新环境可以按照规划中的主机名更改,并且参照上篇中的环境准备工作,重新部署环境后再下载Zookeeper,也可以加入ansible方便后续操控
本张文档作为中篇Zookeeper单在部署方面与上面的Hadoop没有关系,但需要ZK的管理等其他测试需要开启上篇中的Hadoop集群联合部署
# 停止之前运行的 hadoop的hdfs和yarn服务
/usr/local/hadoop/sbin/stop-all.sh
五、部署Zookeeper集群
解压tar包,并拷贝至/usr/local目录下
tar -zxf ./apache-zookeeper-3.8.6-bin.tar.gz -C /usr/local/
mv /usr/local/apache-zookeeper-3.8.6 /usr/local/zookeeper
# 解压并重命名
tar -zxf ./apache-zookeeper-3.8.6-bin.tar.gz -C /usr/local/ --transform='s/apache-zookeeper-3.8.6/zookeeper/'
更改zoo.cfg配置文件
server.id:动态集群配置,id唯一不重复并且与myid一致,后面添加hosts解析的主机名(或ip地址):port1:port2,其中observer需要独立声明
clientPort: 客户端连接端口,默认2181
dataDir:数据存储目录,默认/tmp/zookeeper,但由于systemd的 tmpfiles.d 机制导致定期清理或重启清空tmp目录,所以更改为/var/zookeeper
tickTime:设置ZK集群的基本时间单元,心跳和超时以此为基准,默认值2000ms
initLimit: Follower连接Leader的初始化超时(值 × tickTIme),默认5(5 × 2000ms = 10000ms)
syncLimit: Follower与Leader同步的超时(值 × tickTIme),默认2(2 × 2000ms = 4000ms)
# 更改前先备份
cp /usr/local/zookeeper/conf/zoo_sample.cfg /usr/local/zookeeper/conf/zoo.cfg
# 配置集群添加节点信息
echo "
dataDir=/var/zookeeper
# server.id 其中id与myid一一对应
server.1=node1:2888:3888 # 2888:Follower 与 Leader 之间的数据同步和心跳通信端口
server.2=node2:2888:3888 # 3888:节点间选举投票通信端口
server.3=node3:2888:3888
server.4=node4:2888:3888:observer" >> /usr/local/zookeeper/conf/zoo.cfg
注意:如果默认配置文件不做修改,zookeeper会启动单机模式

配置myid,在zookeeper的data目录下创建myid文件,并写入对应节点的编号;而且myid编号与zookeeper配置文件内新增的server.id的编号必须一致并且唯一,id范围在1-255
# 创建数据目录
mkdir /var/zookeeper
# 创建myid文件并写入对应编号
echo "1" > /var/zookeeper/myid
同步zookeeper文件至其他集群节点
# 同步zookeeper文件至其他节点
for node in node2 node3 node4; do
rsync -axSH --delete /usr/local/zookeeper $node:/usr/local/
done
# 同步在其他节点生成myid文件
for i in 2 3 4; do
ssh node$i "mkdir /var/zookeeper && echo $i > /var/zookeeper/myid"
done
六、启动Zookeeper集群
启动集群
# 启动zookeeper
for node in node1 node2 node3 node4; do
ssh $node "/usr/local/zookeeper/bin/zkServer.sh start"
done
# 查看状态
for node in node1 node2 node3 node4; do
ssh $node "/usr/local/zookeeper/bin/zkServer.sh status"
done
# 如果需要配置ZK自启,需要配置systemd管理文件
cat >> /etc/systemd/system/zookeeper.service << 'EOF'
[Unit]
Description=Apache ZooKeeper
After=network.target
[Service]
Type=forking
User=root
Environment="JAVA_HOME=/usr/lib/jvm/java-17-openjdk"
ExecStart=/usr/local/zookeeper/bin/zkServer.sh start
ExecStop=/usr/local/zookeeper/bin/zkServer.sh stop
ExecReload=/usr/local/zookeeper/bin/zkServer.sh restart
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
注意:启动顺序没有要求,但必须保证集群中半数以上的节点都启动,否则无法查看状态会报错,因为可投票的机器数量少于一半

集群客户端基本操作
ZooKeeper自带命令行客户端工具 zkCli.sh,位于集群根目录的 bin 下
# 连接本地节点(默认端口2181)
/usr/local/zookeeper/bin/zkCli.sh
# 连接指定节点和端口
/usr/local/zookeeper/bin/zkCli.sh -server node1:2181
# 连接集群(客户端自动选择可用节点)
/usr/local/zookeeper/bin/zkCli.sh -server node1:2181,node2:2181,node3:2181
# 查看根目录下的子节点
[zk: node1:2181(CONNECTED) 0] ls /
# 查看 /zookeeper 节点及其子节点的状态信息(递归)
[zk: node1:2181(CONNECTED) 1] ls -s /zookeeper
# 创建持久节点(存储数据 "namenode-host")
[zk: node1:2181(CONNECTED) 2] create /hadoop/hdfs/namenode "namenode-host"
Created /hadoop/hdfs/namenode
# 创建持久节点(不存储数据)
[zk: node1:2181(CONNECTED) 3] create /hadoop/yarn ""
Created /hadoop/yarn
# 创建临时节点(-e 参数,当前会话关闭后自动删除)
[zk: node1:2181(CONNECTED) 4] create -e /hadoop/hdfs/namenode/active "master:9870"
Created /hadoop/hdfs/namenode/active
# 创建持久顺序节点(-s 参数,路径末尾自动追加序号)
[zk: node1:2181(CONNECTED) 5] create -s /hadoop/lock/task- ""
Created /hadoop/lock/task-0000000001
# 创建临时顺序节点(-e -s 组合)
[zk: node1:2181(CONNECTED) 6] create -e -s /hadoop/lock/task- ""
Created /hadoop/lock/task-0000000002

ZooKeeper还支持轻量级的命令,适合在无法访问HTTP端口时快速排查问题
# 需要在zoo.cfg中添加配置(3.5+ 默认只开放部分命令)
4lw.commands.whitelist=*
# 使用方式:通过telnet或nc发送
echo ruok | nc node1 2181 # 返回 imok 表示健康
echo stat | nc node1 2181 # 查看节点状态
echo mntr | nc node1 2181 # 查看监控指标
echo conf | nc node1 2181 # 查看配置信息
echo cons | nc node1 2181 # 查看连接列表
echo wchs | nc node1 2181 # 查看 Watch 汇总
七、Zookeeper集群远程管理
AdminServer管理
ZooKeeper从 3.5.0版本起内置了AdminServer,它是一个基于 Jetty的HTTP服务,提供REST风格的API接口来查看和管理ZooKeeper集群状态。相比第三方工具(如zkui),AdminServer无需额外部署,配置简单且与 ZooKeeper版本保持同步更新,作为集群管理工具更加轻量可靠
## 启动AdminServer
#在zoo.cfg中追加以下配置
cat >> /usr/local/zookeeper/conf/zoo.cfg << 'EOF'
# AdminServer 配置
admin.enableServer=true
admin.serverPort=8080 # 8080可能会与comcat或nginx服务冲突,注意验证端口可用
admin.serverAddress=0.0.0.0
EOF
# 与其他节点同步配置文件
for node in node2 node3 node4; do
rsync -axSH --delete /usr/local/zookeeper/conf/zoo.cfg $node:/usr/local/zookeeper/conf/;
done
# 重启所有节点(需逐个重启,避免集群不可用)
for node in node1 node2 node3 node4; do
ssh $node "/usr/local/zookeeper/bin/zkServer.sh restart"
done
# 测试AdminServer
curl http://node1:8080/commands/stat
# 在浏览器中访问 'http://192.168.8.21:8080/commands'

zkui管理
案例选择zkui可视化工具辅助管理,从github拉取源码包,通过maven编译得到成品 jar包,再运行
# 安装mvn工具
dnf install -y maven
# 从github拉取源码包
cd /ansible/package & git clone https://github.com/DeemOpen/zkui.git
# 编译 jar包
cd /ansible/package/zkui & mvn clean package -DskipTests


更改config.cfg配置内容
# 更改端口和ZK集群ip端口信息
serverPort=9099
zkServer=192.168.8.21:2181,192.168.8.22:2181,192.168.8.23:2181
# 案例测试仅更改端口和ZK信息,其他可按需更改登录用户名密码、jdbc、连接超时等
启动zkui服务
# 临时启动zkui服务
nohup java -jar zkui-2.0-SNAPSHOT-jar-with-dependencies.jar > zkui.log 2>&1 &
## 将zkui托管为systemd管理
# 将jar包与cfg配置文件拷贝至/usr/local/zkui
mkdir /usr/local/zkui/
cp /ansible/package/zkui/target/{zkui*dependencies.jar,config.cfg} /usr/local/zkui/
# 设置service文件
cat >> /etc/systemd/system/zkui.service << 'EOF'
[Unit]
Description=Zkui - Zookeeper Web UI
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/usr/local/zkui
ExecStart=/usr/bin/java -jar /usr/local/zkui/zkui-2.0-SNAPSHOT-jar-with-dependencies.jar
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
## 目录结构
/usr/local/zkui
├── zkui-2.0-SNAPSHOT-jar-with-dependencies.jar # jar 包
├── config.cfg # 配置文件
└── zkui.log # 日志(可选)
注意:临时启动时,将config.cfg文件拷贝至target目录并进入目录后再启动 jar包服务,这样 jar包会读取当前目录下的cfg文件,否则 jar包会默认读取根目录下的cfg源文件
在systemd管理中,jar包是通过WorkingDirectory目录下查找cfg文件


zkui服务开启后在web端登录,在config配置文件中有默认用户名密码:admin,manager

更多管理方式参考管理文档:https://zookeeper.apache.org/doc/r3.8.6/zookeeperAdmin.html
更多推荐
所有评论(0)