2 ZooKeeper
2.1 ZooKeeper使用场景
ZooKeeper是一个分布式服务框架, 它主要是用来解决分布式应用中经常遇到的一些数据管理问题, 如: 命名服务, 状态同步, 配置中心, 集群管理等
- 命名服务: 命令服务是分布式系统中比较常见的一类场景. 命名服务是分布式系统最基本的公共服务之一. 在分布式系统中, 被命名的实体通常可以是集群中的机器, 提供的服务地址或远程对象等. 这些我们都可以统称为名字, 其中较为常见的就是一些分布式服务框架(如 RPC, RMI)中的服务地址列表, 通过使用命名服务, 客户端应用能够根据指定名字来获取资源的实体, 服务地址和提供者的信息等.
-
状态同步: 解决微服务场景下, 服务动态扩容或者缩容时, 服务动态发现的问题. 不同的服务会将自己注册到ZooKeeper, 消费者通过连接ZooKeeper去获得服务的地址. 无论是微服务扩容还是服务宕机, ZooKeeper都会同步给消费者, 保证消费者连接的都是可用的最新的服务地址
每个节点除了存储数据内容和node节点状态信息之外, 还存储了已经注册的APP状态信息, 当有些节点或APP不可用, 就将当前状态同步给其他服务.
-
配置中心: 现在我们大多数应用都是采用的是分布式开发的应用, 搭建到不同的服务器上, 对于配置文件, 同一个应用程序的配置文件一样, 还有就是多个程序存在相同的配置, 当我们配置文件中有个配置属性需要改变, 我们需要改变每个程序的配置属性, 这样会很麻烦的去修改配置, 那么可以使用ZooKeeper来实现配置中心. ZooKeeper采用的是推拉相结合的方式: 客户端向服务端注册自己需要关注的节点, 一旦该节点的数据发生变更, 那么服务端就会向相应的客户端发送Watcher事件通知, 客户端接收到这个消息通知后, 需要主动到服务端获取最新的数据
-
集群管理: 所谓的集群管理, 包括集群监控与集群控制两大块, 前者侧重对集群运行时状态的收集, 后者则是对集群进行操作和控制, 在日常开发和运维过程中, 我们经常会有类似于如下的需求:
希望知道当前集群中究竟有多少机器在工作
对集群中每台机器的运行时状态进行数据收集
对集群中机器进行上下线操作
ZooKeeper具有以下两大特性
- 客户端如果对ZooKeeper的一个数据节点注册Watcher监听, 那么当该数据节点的内容或是其子节点列表发生变更时, ZooKeeper服务器就会向订阅的客户端发送变更通知. 对在ZooKeeper上创建的临时节点, 一旦客户端与服务器之间的会话失效, 那么该临时节点也就会被自动清除
- Watcher(事件监听器), 是ZooKeeper中的一个很重要的特性. ZooKeeper允许用户在指定节点上注册一些Watcher,. 并且在一些特定事件触发的时候, ZooKeeper服务端会将事件通知到感兴趣的客户端上去, 该机制是ZooKeeper实现分布式协调服务的重要特性
0 生产者启动
1 生产者注册至ZooKeeper
2 消费者启动并订阅频道
3 ZooKeeper通知消费者事件
4 消费者调用生产者
5 监控中心负责统计和监控服务状态
2.2 ZooKeeper单机安装
单机版的ZooKeeper安装
10.0.0.209
2.2.1 配置Java环境
官方依赖介绍: https://zookeeper.apache.org/doc/r3.4.14/zookeeperAdmin.html#sc_requiredSoftware
root@zookeeper:~# apt install openjdk-8-jdk -y
2.2.2 部署ZooKeeper-3.5.8
下载二进制包: https://archive.apache.org/dist/zookeeper/zookeeper-3.5.8/
root@zookeeper:~# mkdir /apps
root@zookeeper:~# cd /apps
root@zookeeper:/apps# rz -E
rz waiting to receive.
root@zookeeper:/apps# ls
apache-zookeeper-3.5.8-bin.tar.gz
root@zookeeper:/apps# tar xvf apache-zookeeper-3.5.8-bin.tar.gz
root@zookeeper:/apps# cd apache-zookeeper-3.5.8-bin/bin
root@zookeeper:/apps/apache-zookeeper-3.5.8-bin/bin# ll
total 64
drwxr-xr-x 2 root root 4096 May 4 2020 ./
drwxr-xr-x 6 root root 4096 Dec 15 15:54 ../
-rwxr-xr-x 1 root root 232 May 4 2020 README.txt*
-rwxr-xr-x 1 root root 2067 May 4 2020 zkCleanup.sh*
-rwxr-xr-x 1 root root 1158 May 4 2020 zkCli.cmd*
-rwxr-xr-x 1 root root 1621 May 4 2020 zkCli.sh* #Linux客户端脚本, 可以连接到ZooKeeper服务器执行操作
-rwxr-xr-x 1 root root 1766 May 4 2020 zkEnv.cmd*
-rwxr-xr-x 1 root root 3690 May 4 2020 zkEnv.sh*
-rwxr-xr-x 1 root root 1286 May 4 2020 zkServer.cmd*
-rwxr-xr-x 1 root root 4573 May 4 2020 zkServer-initialize.sh*
-rwxr-xr-x 1 root root 9386 May 4 2020 zkServer.sh* #Linux服务启动脚本
-rwxr-xr-x 1 root root 996 May 4 2020 zkTxnLogToolkit.cmd*
-rwxr-xr-x 1 root root 1385 May 4 2020 zkTxnLogToolkit.sh*
2.2.3 编辑配置文件
root@zookeeper:/apps/apache-zookeeper-3.5.8-bin/conf# ll
total 20
drwxr-xr-x 2 root root 4096 May 4 2020 ./
drwxr-xr-x 6 root root 4096 Dec 15 15:54 ../
-rw-r--r-- 1 root root 535 May 4 2020 configuration.xsl
-rw-r--r-- 1 root root 2712 May 4 2020 log4j.properties
-rw-r--r-- 1 root root 922 May 4 2020 zoo_sample.cfg #模板配置文件
root@zookeeper:/apps/apache-zookeeper-3.5.8-bin/conf# cp zoo_sample.cfg zoo.cfg
root@zookeeper:/apps/apache-zookeeper-3.5.8-bin/conf# vim zoo.cfg
# The number of milliseconds of each tick
tickTime=2000 #集群中, 定义每次选举的时间
# The number of ticks that the initial
# synchronization phase can take
initLimit=10 #集群中, 定义初始化次数的超时时间
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5 #集群中, 数据同步成功的超时次数
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
# dataDir=/tmp/zookeeper #ZooKeeper数据目录的保存位置
dataDir=/apps/apache-zookeeper-3.5.8-bin/data
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
2.2.4 启动ZooKeeper
root@zookeeper:/apps/apache-zookeeper-3.5.8-bin/bin# ./zkServer.sh start
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/apache-zookeeper-3.5.8-bin/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
2.2.5 验证ZooKeeper进程
root@zookeeper:/apps/apache-zookeeper-3.5.8-bin/bin# ./zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/apache-zookeeper-3.5.8-bin/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: standalone #单机模式
root@zookeeper:/apps/apache-zookeeper-3.5.8-bin/bin# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 50 *:8080 *:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 50 *:46813 *:*
LISTEN 0 50 *:2181 #ZooKeeper监听2181端口 *:*
2.2.6 测试数据写入
#!/usr/bin/env python
def myzk():
from kazoo.client import KazooClient
zk = KazooClient(hosts='10.0.0.209:2181')
zk.start()
zk.create('/zoo/data',makepath=True) #makepath=True 递归创建目录
ret=zk.set('/zoo/data',"Hello World")
data=zk.get("/zoo/data")
print(data)
zk.stop()
myzk()
2.2.7 利用客户端脚本, 操作ZooKeeper
root@zookeeper:/apps/apache-zookeeper-3.5.8-bin/bin# ./zkCli.sh
...
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper] #zookeeper相当于/下的一个目录
[zk: localhost:2181(CONNECTED) 1] ls /zookeeper
[config, quota] #config, quota相当于zookeeper目录里的key
[zk: localhost:2181(CONNECTED) 6] get /zookeeper/quota #get命令查看一个key的值, 这里quota默认没有value
还原虚拟机准备集群搭建
2.3 ZooKeeper集群
图片.png图片.png
图片.png 图片.png
ZooKeeper集群用于解决单点和单机性能及数据高可用等问题
ZooKeeper是复制集群, 数据在每个节点都是相同的
通过选举, 选出一个唯一的leader, 数据的写入只通过leader写入, 因为如果通过其他节点写入, 无法保证数据一致性
客户端连接到follower后写入数据, follower会把数据路由给leader, 由leader完成数据写入, leader完成写入后, 会把数据同步到其他follower节点. 消费者可以连接到任意节点去消费数据. 如果leader宕机, 剩余节点会再次选举出一个leader
ZooKeeper特性1:
写操作的"过半写成功策略": 用来判断数据何时被认为写入完毕
举例. 当有五个节点, 其中一个Leader节点, 四个Follower节点时
客户端发起数据写入操作, 会由连接的follower把数据路由给leader, 由leader完成数据写入, 再由leader同步给其他的follower节点. 过半写成功策略就规定了, 集群中, 有半数以上完成了数据写入, 就认为数据写入完毕, 返回给客户端数据写入完毕, 之后再由leader把数据同步到其余未完成数据写入的节点, 有助于写入性能提供
2.4 集群部署
zookeeper 集群特性:整个集群中只要有超过集群数量一半的 zookeeper 工作是正常的,那么整个集群对外就是可用的,假如有 2 台服务器做了一个 zookeeper集群,只要有任何一台故障或宕机,那么这个zookeeper 集群就不可用了,因为剩下的一台没有超过集群一半的数量,但是假如有三台 zookeeper 组成一个集群,那么损坏一台就还剩两台,大于 3 台的一半,所以损坏一台还是可以正常运行的,但是再损坏一台就只剩一台集群就不可用了。那么要是 4 台组成一个zookeeper 集群,损坏一台集群肯定是正常的,那么损坏两台就还剩两台,那么2 台不大于集群数量的一半,所以 3 台的 zookeeper 集群和 4 台的 zookeeper 集群损坏两台的结果都是集群不可用,以此类推 5 台和 6 台以及 7 台和 8 台都是同理,所以这也就是为什么集群一般都是奇数的原因。
集群环境
Zoo1 - 10.0.0.209
Zoo2 - 10.0.0.199
Zoo3 - 10.0.0.189
- 三台ZooKeeper安装jdk
apt install openjdk-8-jdk -y
- 将ZooKeeper二进制包上传到/apps并解压
mkdir /apps
cd /apps
tar xvf apache-zookeeper-3.5.8-bin.tar.gz
- 创建软连接
ln -sv apache-zookeeper-3.5.8-bin/ /apps/zookeeper
- 创建ZooKeeper数据目录
mkdir /apps/zookeeper/data
- 配置文件修改
拷贝模板文件
cp /apps/zookeeper/conf/zoo_sample.cfg /apps/zookeeper/conf/zoo.cfg
三个服务器的配置文件相同
vim /apps/zookeeper/conf/zoo.cfg
...
dataDir=/apps/zookeeper/data
...
maxClientCnxns=128 #单个客户端IP可以和ZooKeeper保持的连接数
autopurge.snapRetainCount=16
autopurge.purgeInterval=6
server.1=10.0.0.209:2888:3888
server.2=10.0.0.199:2888:3888
server.3=10.0.0.189:2888:3888
tickTime=2000 #服务器与服务器之间的单次心跳检测时间间隔,单位为毫秒
initLimit=10 #集群中 leader 服务器与 follower 服务器初始连接心跳次数,即多少个 2000 毫秒
syncLimit=5 # leader 与 follower 之间连接完成之后,后期检测发送和应答的心跳次数,如果该 follower 在设置的时间内(5*2000)不能与 leader 进行通信,那么此 follower 将被视为不可用。
dataDir=/usr/local/zookeeper/data #自定义的 zookeeper 保存数据的目录
clientPort=2181 #客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求
maxClientCnxns=128 #单个客户端 IP 可以和 zookeeper 保持的连接数
autopurge.snapRetainCount=3 #3.4.0 中的新增功能:启用后,ZooKeeper 自动清除功能会将autopurge.snapRetainCount 最新快照和相应的事务日志分别保留在 dataDir 和 dataLogDir 中,并删除其余部分,默认值为 3。最小值为 3。就是保存快照的数量.
autopurge.purgeInterval=1 # 3.4.0 及之后版本,ZK 提供了自动清理日志和快照文件的功能,这个参数指定了清理频率,单位是小时,需要配置一个 1 或更大的整数,默认是 0,表示不开启自动清理功能
server.1=172.18.0.101:2888:3888 # server.服务器编号=服务器 IP:LF 数据同步端口:LF 选举端口
server.2=172.18.0.102:2888:3888 # leader监听2888
server.3=172.18.0.103:2888:3888 # leader和follower都会监听3888
三个节点分别生成自己的myid文件
root@zoo1:~# echo "1" > /apps/zookeeper/data/myid
root@zoo2:~# echo "2" > /apps/zookeeper/data/myid
root@zoo3:~# echo "3" > /apps/zookeeper/data/myid
- 分别启动ZooKeeper
/apps/zookeeper/bin/zkServer.sh start
- 查看集群状态
此时可以观察到10.0.0.189被选举为leader
root@Zoo1:/apps/zookeeper/data# /apps/zookeeper/bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: follower
root@Zoo2:/apps/zookeeper/data# /apps/zookeeper/bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: follower
root@Zoo3:/apps/zookeeper/data# /apps/zookeeper/bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: leader
root@Zoo1:~# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 50 *:2181 *:*
LISTEN 0 50 *:37935 *:*
LISTEN 0 50 [::ffff:10.0.0.209]:3888 *:*
LISTEN 0 50 *:8080 *:*
root@Zoo2:~# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 50 *:2181 *:*
LISTEN 0 50 *:35531 *:*
LISTEN 0 50 [::ffff:10.0.0.199]:3888 *:*
LISTEN 0 50 *:8080 *:*
LISTEN 0 128 [::]:22 [::]:*
root@Zoo3:~# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 50 *:2181 *:*
LISTEN 0 50 [::ffff:10.0.0.189]:2888 *:*
LISTEN 0 50 *:35053 *:*
LISTEN 0 50 [::ffff:10.0.0.189]:3888 *:*
LISTEN 0 50 *:8080 *:*
- 选举过程
- 节点角色状态
LOOKING:寻找 Leader 状态,处于该状态需要进入选举流程
LEADING:领导者状态,处于该状态的节点说明是角色已经是 Leader
FOLLOWING:跟随者状态,表示 Leader 已经选举出来,当前节点角色是follower
OBSERVER:观察者状态,表明当前节点角色是 observer
- 选举id
ZXID(zookeeper transaction id):每个改变 Zookeeper 状态的操作都会形成一个对应的 zxid。
myid:服务器的唯一标识(SID),通过配置 myid 文件指定,集群中唯一。
- 选举过程
当集群中的 zookeeper 节点启动以后,会根据配置文件中指定的 zookeeper 节点地址进行 leader 选择操作,过程如下:
- 每个 zookeeper 都会发出投票,由于是第一次选举 leader,因此每个节点都会把自己当做 leader 角色进行选举,每个 zookeeper 的投票中都会包含自己的 myid 和 zxid,此时 zookeeper 1 的投票为 myid 为 1,初始 zxid 有一个初始值,后期会随着数据更新而自动变化,zookeeper2 的投票为 myid 为 2,初
始 zxid 为初始生成的值。 - 每个节点接受并检查对方的投票信息,比如投票时间、是否状态为 LOOKING状态的投票。
- 对比投票,优先检查 zxid,如果 zxid不一样则 zxid大的为 leader,如果 zxid相同则继续对比 myid,myid 大的一方为 leader
成为 Leader 的必要条件: Leader 要具有最高的 zxid;当集群的规模是 n 时,
集群中大多数的机器(至少 n/2+1)得到响应并 follow 选出的 Leader。
心跳机制:Leader 与 Follower 利用 PING 来感知对方的是否存活,当 Leader 无
法响应 PING 时,将重新发起 Leader 选举。
新集群, 由于没有数据, zxid在各个节点相同, 因此, 一般会比较myid, 集群运行后, zxid会随着数据的插入而发生变化, 哪个节点的数据越新, zxid值就会越大, 就会被选举为leader
- 各节点的选择日志
cat /apps/zookeeper/logs/zookeeper-root-server-Zoo3.out
- 测试数据同步
分别在三台节点, 通过命令行工具连接到本地ZooKeeper
/apps/zookeeper/bin/zkCli.sh
zoo1上创建数据
[zk: localhost:2181(CONNECTED) 0] create /test "hello" # 通过命令行是无法递归创建目录的
Created /test
zoo2查看
[zk: localhost:2181(CONNECTED) 0] get /test
hello
zoo3查看
[zk: localhost:2181(CONNECTED) 0] get /test
hello
- ZooKeeper数据存放
ZooKeeper数据存放在配置文件中定义的数据目录下的version-x/log文件里, 因此要对数据目录做定期备份
由于三个服务器的数据都是相同的, 因此备份一个客户端的即可
cat /apps/zookeeper/data/version-2/log.100000001
ZKLG"$*,pvf¦ÿN=$V8Pvf§C@ÿÿÿ|c $ vf§Hu0B&
R*,pvf©A/testhelloworldanyoneB
- ZooKeeper监控
- Zabbix监控各个节点的各个端口
- 执行客户端zkCli.sh命令, 进入ZooKeeper,再退出, 检查命令是否执行成功
- Zookeeper客户端在Linux平台使用
- 客户端编译
root@zooinsepect:~# apt install git maven openjdk-8-jdk -y
root@zooinsepect:~# git clone https://github.com/zzhang5/zooinspector.git
root@zooinsepect:~# cd /zooinspector
root@zooinsepect:~/zooinspector# mvn clean package
图片.png
- 客户端使用
root@Zoo1:~/zooinspector# chmod +x target/zooinspector-pkg/bin/zooinspector.sh
root@Zoo1:~/zooinspector# export DISPLAY=10.0.0.1:0.0
Windows开启Xmanager
修改xshell配置
图片.pngroot@Zoo1:~/zooinspector# target/zooinspector-pkg/bin/zooinspector.sh
图片.png
图片.png
网友评论