Zookeeper 提供单机和集群两种搭建方式,在生产环境中通常使用集群部署的方式来提高可用性。其作为分布式协调服务,应保持数据的一致性。
Zookeeper 集群是一个 CP(一致性+分区容错性)的分布式系统,任何时刻对正常工作的 Zookeeper 集群的任意节点发起的请求都尽量得到一致的数据结果,对于Zookeeper的操作是原子性的,只有成功和失败,不存在只产生部分结果的情况。
集群数量
为了防止“脑裂”的问题,Zookeeper 集群规定了仅有半数以上的节点之间可以互相通信、正常工作时,Zookeeper 才会对外提供服务,如果因为网络分割等故障导致集群中未达到配置的一半节点, 那么 Zookeeper 会认为自己是被分割的少数不可用那一方,会将自己也从可用节点中剔除,不对外提供服务。
- 如果集群中有2个节点,那么只要宕机1个节点,集群就不可用了。此时,集群对节点不可用的容忍度为0;
- 如果集群中有3个节点,那么宕机1个节点,还有2个正常节点,此时正常工作的节点仍然超过半数,在重新选举后可以正常服务。此时,集群对节点不可用的容忍度为1;
- 如果集群中有4个节点,那么宕机1个节点,还有3个正常节点,此时正常工作的节点超过半数,在重新选举后可以正常服务。但如果再宕机1个节点,只剩下2个未超过半数,此时集群已经无法正常选举和服务了。集群对节点不可用的容忍度1;
- 如果集群中有5个节点,半数以上至少需要3个节点正常工作,集群对节点不可用的容忍度为2;
- 如果集群中有6个节点,半数以上至少需要4个节点正常工作,集群对节点不可用的容忍度为仍然为2;
- …
依次类推可以发现,集群中有2n个节点和2n-1个节点时的节点不可用容忍度是一样的。由于节点正常工作时同步数据、集群通信、投票选举也需要消耗一定的资源,直接减少一个节点反而可以更高效的利用服务器资源。
一般 Zookeeper 集群都是采用奇数节点来部署的,主要是为了更高效的利用服务器资源,推荐 Zookeeper 集群中至少有三个节点。虽然最低只需要两个节点即可组成集群,但由两个节点组成的 Zookeeper 集群只要其中一个宕机/网络分割而导致集群未满足“过半”的要求,这时另一个正常的节点也因为集群中节点未达到半数而无法提供服务了。
在集群中每个节点都有一个在集群中唯一的myid
,这个id由数字组成,数字范围为1~255
之间,如果启动了TTL节点的扩展功能,id的范围就又缩小到了1~254
,由此可见在一个Zookeeper集群中理论最多可以拥有255个节点。因为节点正常工作时同步数据、集群通信、投票选举也需要消耗一定的资源,需要选择合适的数量,不宜将集群的规模设置的过大。
集群数据同步
Zookeeper 集群中同步数据采用的是ZAB算法来保证数据的一致性,所有的写请求都由Leader执行,即使客户端请求到了Follower节点也会被转发过去。
各个节点之间保证数据写入顺序的一致性,并且要求半数以上的节点写入成功才会提交事务。 此时可能有部分节点没有完成数据的同步,如果客户端请求恰好发往未完成数据同步的节点,就会获取到最后一次更新时的数据。但所有节点最终都会按照严格的顺序同步为相同的数据。
集群选举
集群角色
Zookeeper 集群中的节点有以下角色:
- Leader: 负责更新系统状态,为客户端提供读和写服务
- Follower: 负责接受客户端请求和响应结果,在选取新主节点时参与投票,为客户端提供读服务。
- Observer: 接受客户端连接并转发请求给leader,不参与投票过程,只同步leader状态。主要用于扩展系统,提高集群的读取性能。
在集群竞选的过程中,节点的状态有以下几种,可以使用 zkServer.sh status
查看他们的状态:
- Looking:竞选状态
- Leading:领导者状态
- Following:跟随者状态,同步Leader状态,并参与投票
- Observing:观察状态,同步Leader状态,不参与投票
选举场景
在整个Zookeeper集群刚刚启动时,此时集群中还没有Leader,会进行一次Leader选举。
Leader节点所在的服务器宕机/网络故障等情况会导致Leader失效,剩余节点会重新进行选举推出新的Leader。
集群搭建
准备工作
安装JDK,并配置
JAVA_HOME
环境变量。Zookeeper在运行一段时间后,可能占用较多的空间,在部署前需要查看服务器挂载磁盘空间信息,避免磁盘空间不足导致无法正常提供服务。
1
2
3
4
5
6
7
8
9
10
11[root@hadoop1 bin]# df -h
文件系统 容量 已用 可用 已用% 挂载点
devtmpfs 63G 0 63G 0% /dev
tmpfs 63G 0 63G 0% /dev/shm
tmpfs 63G 12M 63G 1% /run
tmpfs 63G 0 63G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 2.3G 48G 5% /
/dev/sda1 1014M 150M 865M 15% /boot
/dev/mapper/centos-home 418G 6.4G 411G 2% /home
tmpfs 13G 0 13G 0% /run/user/0
tmpfs 13G 0 13G 0% /run/user/1000执行
df –h
命令后可以看到,空间最大的数据盘挂载目录为/home
目录,将Zookeeper部署到该目录下。
3.如果没有特殊需求,直接获取前往官网获取打包好的二进制包即可。
4.部署过程中如无特殊说明,则在每台服务器上都执行一样的操作。
集群规划
主机IP | 对外提供服务端口 | 选举Leader端口 | 节点间通讯端口 |
---|---|---|---|
10.231.176.18 | 2181 | 3888 | 2888 |
10.231.176.19 | 2181 | 3888 | 2888 |
10.231.176.20 | 2181 | 3888 | 2888 |
Zookeeper部署目录为 /home/zookeeper/apache-zookeeper-3.9.1-bin
,数据目录为 /home/zookeeper/apache-zookeeper-3.9.1-bin/data
部署过程
解压Zookeeper到规划目录。并创建存放数据的data目录。
1
2
3cd /home && mkdir zookeeper
tar -zxvf apache-zookeeper-3.9.1-bin.zip && mv apache-zookeeper-3.9.1-bin /home/zookeeper
cd zookeeper/apache-zookeeper-3.9.1-bin && mkdir data为不同节点分配各自唯一的
myid
,取值必须为数字且在1~254之间。为10.231.176.18服务器单独配置:
1
[root@hadoop1 ~]# echo 1 > /home/zookeeper/apache-zookeeper-3.9.1-bin/data/myid
为10.231.176.19服务器单独配置:
1
[root@hadoop2 ~]# echo 2 > /home/zookeeper/apache-zookeeper-3.9.1-bin/data/myid
为10.231.176.20服务器单独配置:
1
[root@hadoop3 ~]# echo 3 > /home/zookeeper/apache-zookeeper-3.9.1-bin/data/myid
执行
vi conf/zoo.cfg
新增以下配置文件1
2
3
4
5
6
7
8
9
10tickTime=2000
initLimit=10
syncLimit=5
dataDir=../data
clientPort=2181
# 根据需求决定是否关闭zk admin
admin.enableServer=false
server.1=10.231.176.18:2888:3888
server.2=10.231.176.19:2888:3888
server.3=10.231.176.20:2888:3888其中
server.x
对应着myid
文件中配置的数值;2888为节点间交换信息使用的端口,只要端口没有冲突可根据需求指定其他端口;
3888为选举Leader使用的端口,只要端口没有冲突可根据需求指定其他端口;
赋予脚本可执行权限
1
2cd bin
chmod 755 zkEnv.sh && chmod 755 zkServer.sh && chmod 755 zkCli.sh启动服务
1
./zkServer start
查看节点状态
1
2
3
4
5[root@hadoop1 bin]# ./zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /home/zookeeper/apache-zookeeper-3.9.1-bin/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower
执行查看启动状态命令,只要输出的最后一行不是“Error contacting service. It is probably not running.”,那么Zookeeper集群已经部署完成并且可以对外提供服务了。