Zookeeper 跨区高可用方案

最近因为业务需求,测试各类组件的高可用性。因为咱们的环境在AWS 北京部署。只有两个Aviable Zone(可用区)。php

注释:有两个数据中心,相互须要作容灾的需求,和本文测试的状况是相同的。html

而Zookeeper须要3个以上的单数节点同时工做,而且,必须保证半数以上的节点存活,还能正常提供服务。java

那么,针对只有两个AZ的状况,无论怎么规划,都有几率遇到存在半数以上的AZ挂掉,致使整个Zookeeper不可用的状况。node

clipboard.png

因此,咱们能作的就是,在这个AZ挂掉以后,咱们怎么尽快处理,并恢复环境。apache

咱们准备两个软件安装好,参数配置好的机器。在可用区1彻底挂掉以后,能够手动启动两个备用节点。将可用区2的Zookeeper数量增长过半数。就能够在可用区2恢复Zookeeper的服务。api

参考下图:服务器

2.png

以上的设想,是否能实现呢?session

那咱们今天就来测试一下。socket

1. 一共准备了5台机器,做为测试ide

3.png

2. Zookeeper的下载与安装。

2.1 Zookeeper官方下载地址

https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/


2.2 下载软件

wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz

2.3 详细Zookeeper安装步骤,请参考:

https://blog.51cto.com/hsbxxl/1971241

2.4 zoo.cfg的配置 #cat zoo.cfg

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=6
server.1=172.31.9.73:2888:3888
server.2=172.31.20.233:2888:3888
server.3=172.31.26.111:2888:3888
server.4=172.31.17.68:2888:3888
server.5=172.31.16.33:2888:3888

2.5  根据zoo.cfg建立data和log两个文件夹

mkdir -p /data/zookeeper/data 
mkdir -p /data/zookeeper/log

2.6 根据节点号码,修改文件

echo 1 > /data/zookeeper/data/myid

3. 一共准备了5台EC2进行测试,而且都已经安装好Zookeeper

可是只启动三台,另两个机器做为standby

下图能够看到,已经有三台启动zookeeper,

注意,在Zookeeper启动的过程当中,必须保证三台及以上,zookeeper集群才能正常工做

5.png

4. 接下来,我开始逐个机器关机,看zookeeper的状态

当前leader在zk3上,咱们先关闭zk1,再关闭zk3,看Leader会不会飘到zk2上

4.1 在zk1上执行kill,杀掉进程

[root@ip-172-31-9-73 ~]# jps
12438 Jps
7545 QuorumPeerMain
[root@ip-172-31-9-73 ~]# zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /root/zookeeper-3.4.14/bin/../conf/zoo.cfg
Mode: follower
[root@ip-172-31-9-73 ~]# kill -9 7545

4.2 在zk5上经过zkCli连接zk3,并能够查询数据。

在zk1上kill掉进程以后,理论上,还有zk2和zk3存活,可是zkCli的链接显示已经报错。

[root@ip-172-31-16-33 bin]# ./zkCli.sh -server 172.31.26.111:2181
Connecting to 172.31.26.111:2181
......
[zk: 172.31.26.111:2181(CONNECTED) 0] ls /
[zk-permanent, zookeeper, test]
[zk: 172.31.26.111:2181(CONNECTED) 1] 2019-06-23 07:28:06,581 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1158] - Unable to read additional data from server sessionid 0x30000c504530000, likely server has closed socket, closing socket connection and attempting reconnect
......
2019-06-23 07:28:09,822 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1025] - Opening socket connection to server ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181. Will not attempt to authenticate using SASL (unknown error)
2019-06-23 07:28:09,824 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@879] - Socket connection established to ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181, initiating session
2019-06-23 07:28:09,825 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1158] - Unable to read additional data from server sessionid 0x30000c504530000, likely server has closed socket, closing socket connection and attempting reconnect

4.3 咱们继续 kill掉zk3上的进程,只保留zk2上的进程。可是咱们已经没法确认zk2是Leader仍是Follow,或者说,他是否还保留有数据。

[root@ip-172-31-26-111 bin]# jps
4183 QuorumPeerMain
4648 Jps
[root@ip-172-31-26-111 bin]# kill -9 4183
[root@ip-172-31-26-111 bin]# jps
4658 Jps

4.4 zk3上进程kill掉以后,连接就不仅是上面的报错了,而是直接链接拒绝

[root@ip-172-31-16-33 bin]# ./zkCli.sh -server 172.31.26.111:2181
Connecting to 172.31.26.111:2181
......
Welcome to ZooKeeper!
2019-06-23 07:35:18,411 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1025] - Opening socket connection to server ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181. Will not attempt to authenticate using SASL (unknown error)
JLine support is enabled
2019-06-23 07:35:18,533 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1162] - Socket error occurred: ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181: Connection refused
[zk: 172.31.26.111:2181(CONNECTING) 0] 2019-06-23 07:35:19,639 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1025] - Opening socket connection to server ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181. Will not attempt to authenticate using SASL (unknown error)
2019-06-23 07:35:19,640 [myid:] - INFO  [main-SendThread(ip-172-31-26-111.cn-north-1.compute.internal:2181):ClientCnxn$SendThread@1162] - Socket error occurred: ip-172-31-26-111.cn-north-1.compute.internal/172.31.26.111:2181: Connection refused

4.5 能够看到zk2上的进程还在,

# jps
5155 QuorumPeerMain
5211 Jps

4.6 而且经过下面命令,能够检查到zk2 的2181端口还在提供服务

# echo ruok | nc localhost 2181
imok

4.7 可是其余命令是没有正常输出的,只有echo ruok | nc localhost 2181输出ok。

# echo ruok | nc 172.31.16.33 2181
imok[root@ip-172-31-16-33 bin]# echo conf | nc 172.31.16.33 2181
This ZooKeeper instance is not currently serving requests
# echo dump | nc 172.31.16.33 2181
This ZooKeeper instance is not currently serving requests

4.8  ZooKeeper 四字命令

ZooKeeper 四字命令

功能描述

conf

输出相关服务配置的详细信息。

cons

列出全部链接到服务器的客户端的彻底的链接 / 会话的详细信息。包括“接受 / 发送”的包数量、会话 id 、操做延迟、最后的操做执行等等信息。

dump

列出未经处理的会话和临时节点。

envi

输出关于服务环境的详细信息(区别于 conf 命令)。

reqs

列出未经处理的请求

ruok

测试服务是否处于正确状态。若是确实如此,那么服务返回“imok ”,不然不作任何相应。

stat

输出关于性能和链接的客户端的列表。

wchs

列出服务器 watch 的详细信息。

wchc

经过 session 列出服务器 watch 的详细信息,它的输出是一个与watch 相关的会话的列表。

wchp

经过路径列出服务器 watch 的详细信息。它输出一个与 session相关的路径。

4.9 正常状况下,以上命令能够输出:

# echo dump | nc 172.31.20.233 2181

SessionTracker dump:
org.apache.zookeeper.server.quorum.LearnerSessionTracker@77714302
ephemeral nodes dump:
Sessions with Ephemerals (0):

# echo conf | nc 172.31.20.233 2181

clientPort=2181
dataDir=/data/zookeeper/data/version-2
dataLogDir=/data/zookeeper/log/version-2
tickTime=2000
maxClientCnxns=60
minSessionTimeout=4000
maxSessionTimeout=40000
serverId=2
initLimit=10
syncLimit=5
electionAlg=3
electionPort=3888
quorumPort=2888
peerType=0

# echo envi| nc 172.31.20.233 2181

Environment:
zookeeper.version=3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT
host.name=ip-172-31-20-233.cn-north-1.compute.internal
java.version=1.8.0_212
java.vendor=Oracle Corporation
java.home=/usr/java/jdk1.8.0_212-amd64/jre
java.class.path=/root/zookeeper-3.4.14/bin/../zookeeper-server/target/classes:/root/zookeeper-3.4.14/bin/../build/classes:/root/zookeeper-3.4.14/bin/../zookeeper-server/target/lib/*.jar:/root/zookeeper-3.4.14/bin/../build/lib/*.jar:/root/zookeeper-3.4.14/bin/../lib/slf4j-log4j12-1.7.25.jar:/root/zookeeper-3.4.14/bin/../lib/slf4j-api-1.7.25.jar:/root/zookeeper-3.4.14/bin/../lib/netty-3.10.6.Final.jar:/root/zookeeper-3.4.14/bin/../lib/log4j-1.2.17.jar:/root/zookeeper-3.4.14/bin/../lib/jline-0.9.94.jar:/root/zookeeper-3.4.14/bin/../lib/audience-annotations-0.5.0.jar:/root/zookeeper-3.4.14/bin/../zookeeper-3.4.14.jar:/root/zookeeper-3.4.14/bin/../zookeeper-server/src/main/resources/lib/*.jar:/root/zookeeper-3.4.14/bin/../conf:
java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
java.io.tmpdir=/tmp
java.compiler=<NA>
os.name=Linux
os.arch=amd64
os.version=4.14.123-86.109.amzn1.x86_64
user.name=root
user.home=/root
user.dir=/root/zookeeper-3.4.14/bin

5. 这个时候,我去启动另外两个备用节点,zk4,zk5.这个两个节点都是第一次启动。

6.png

6. 再次链接到zookeeper上,能够看到,至少数据仍是没有丢失的

[root@ip-172-31-16-33 bin]# ./zkCli.sh -server 172.31.16.33:2181
Connecting to 172.31.16.33:2181
......
[zk: 172.31.16.33:2181(CONNECTED) 0] ls /
[zk-permanent, zookeeper, test]

7. 经过以上测试,彷佛是达到咱们预期的结果。惟一的一点小问题,就是:咱们有3个节点,为何关闭1个,剩余两个,就不能正常运行了呢?

其实,这里是有个“想固然”的小问题。

咱们觉得,只启动三个. 其实,Zookeeper集群,识别的是5个, 为何呢?

Zookeeper靠什么去识别集群中有几个节点呢?固然不是靠“想固然”。必定是有配置文件告诉它。Zookeeper,只有两个配置文件zoo.cfg和myid。

那就只有zoo.cfg会影响到它了。

8. 我将zoo.cfg作以下修改以后。只开启3个节点,在关闭一个节点以后,仍是能够正常运行的。

注释掉server2和server5

# cat zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=6
server.1=172.31.9.73:2888:3888
#server.2=172.31.20.233:2888:3888
server.3=172.31.26.111:2888:3888
server.4=172.31.17.68:2888:3888
#server.5=172.31.16.33:2888:3888

9. 关闭server4以后,还有server2和server3活着。

[root@ip-172-31-26-111 ~]# zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /root/zookeeper-3.4.14/bin/../conf/zoo.cfg
Mode: leader
[root@ip-172-31-9-73 ~]# zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /root/zookeeper-3.4.14/bin/../conf/zoo.cfg
Mode: follower

10. 总结,若是考虑两个AZ的状况下,zookeeper节点数多的AZ出现灾难状况,咱们如何快速恢复?

(假设Server1/Server2在1AZ,Server3/Server4/Server5在2AZ)

10.1. 在Zookeeper节点少的AZ,多准备2台配置好zookeeper的EC2,并关机待使用。Server4/Server5具体zoo.cfg配置以下

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=6
server.3=172.31.26.111:2888:3888
server.4=172.31.17.68:2888:3888
server.5=172.31.16.33:2888:3888

10.2.  Server1/Server2/Server3,是正常运行的节点,配置以下:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=6
server.1=172.31.9.73:2888:3888
server.2=172.31.20.233:2888:3888
server.3=172.31.26.111:2888:3888

10.3.  灾难发生,Server1/Server2所在的1AZ挂掉的状况下,须要人工介入,将Server3的配置更改成以下配置,并重启Server3的zookeeper服务,而后启动Server4/Server5,必定要先启动Server3,注意顺序。

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=6
server.3=172.31.26.111:2888:3888
server.4=172.31.17.68:2888:3888
server.5=172.31.16.33:2888:3888

10.4 平常运行状态

7.png

10.5 检查已经建立的znode信息

./zkCli.sh -server 172.31.16.33:2181 ls /
Connecting to 172.31.16.33:2181
[zk-permanent, zookeeper, test]

10.6 关闭Server1/Server2,注意顺序,先关闭follow,若是先关闭leader,会发生切换。咱们指望的是Server3最后以follow的身份存活。


11. 最终能够看到测试结果,一切都是按照咱们“想固然”的方向发展。

8.png

12. 最后验证zookeeper中的znode数据,仍是都存在的。

./zkCli.sh  -server 172.31.16.33:2181 ls /
Connecting to 172.31.16.33:2181
[zk-permanent, zookeeper, test]

13. 其实数据一直是在这个路径下,只要有一个节点还保留,就会保存下去。

# ls /data/zookeeper/data/
myid  version-2  zookeeper_server.pid

注意:必定要保证Server4/Server5的下面两个路径是空的,否则会出现,Server4/Server5识别的是以前的陈旧信息。

/data/zookeeper/data/version-2
/data/zookeeper/log/version-2

14. 说到这里,咱们能够理解到,Zookeeper的所有数据,都是存放在下面两个路径中。若是须要作备份,能够直接在OS层面,作cp备份便可。

dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/log

衍生一个想法,就是若是想作跨Region,北京(主环境)到宁夏(容灾环境)的zookeeper的高可用怎么作呢?

咱们能够考虑将北京的zookeeper的数据文件按期备份,并导入到宁夏的环境。

具体步骤:

<1. 在宁夏启动一个Zookeeper集群,并配置好,而后关闭zookeeper服务,清空掉数据文件夹。

<2. 在北京,经过脚本按期检查zookeeper各个节点状态,从一个运行健康的节点,按期备份数据到S3的一个bucket,为每一个文件加上时间戳。

<3. 经过S3的Cross Region Replication,同步到宁夏。

<4. 而后在宁夏,从S3读取备份文件,并还原到灾备的zookeeper中。

相关文章
相关标签/搜索