本文的目标读者是对 ZooKeeper 有一定理解的技能职员,将从 ZooKeeper 运行模式、集群组成、容灾和水平扩容四方面逐步深入,终极构建出高可用的 ZooKeeper 集群。
Zookeeper 有三种运行模式:单机模式、伪集群模式和集群模式。

1.1 单机模式
这种模式一样平常适用于开拓测试环境,一方面我们没有那么多机器资源,其余便是平时的开拓调试并不须要极好的稳定性。
在 Linux 环境下运行单机模式须要实行以下步骤:
1. 准备 Java 运行环境
安装 Java 1.6 或更高版本的 JDK,并配置好 Java 干系的环境变量 $JAVA_HOME 。
2. 下载 ZooKeeper 安装包3. 配置 zoo.cfg
首次利用 ZooKeeper,须要将 $ZK_HOME 下的 zoo_sample.cfg 文件重命名为 zoo.cfg,并进行以下配置
1
2
3
4
5
6
tickTime=
2000
##Zookeeper最小韶光单元,单位毫秒(ms),默认值为
3000
dataDir=/var/lib/zookeeper ##Zookeeper做事器存储快照文件的目录,必须配置
dataLogDir=/var/lib/log ##Zookeeper做事器存储事务日志的目录,默认为dataDir
clientPort=
2181
##做事器对外做事端口,一样平常设置为
2181
initLimit=
5
##Leader做事器等待Follower启动并完成数据同步的韶光,默认值
10
,表示tickTime的
10
倍
syncLimit=
2
##Leader做事器和Follower之间进行心跳检测的最大延时时间,默认值
5
,表示tickTime的
5
倍
4. 启动做事
利用 $ZK_HOME/bin 目录下的 zkServer.sh 脚本进行做事的启动。
1.2 集群模式
一个 ZooKeeper 集群常日由一组机器组成,一样平常 3 台以上就可以组成一个可用的 ZooKeeper 集群了。
组成 ZooKeeper 集群的每台机器都会在内存中掩护当前的做事器状态,并且每台机器之间都会相互保持通信。
主要的一点是,只要集群中存在超过一半的机器能够正常事情,那么全体集群就能够正常对外做事。
ZooKeeper 的客户端程序会选择和集群中的任意一台做事器创建一个 TCP 连接,而且一旦客户端和做事器断开连接,客户端就会自动连接到集群中的其他做事器。
那么如何运行 ZooKeeper 集群模式呢?首先如果我们有三台做事器,IP 分别为 IP1、IP2和 IP3,则须要实行以下步骤:
1. 准备 Java 运行环境(同上)2. 下载 ZooKeeper 安装包(同上)3. 配置 zoo.cfg
1
2
3
4
5
6
7
8
9
tickTime=
2000
dataDir=/var/lib/zookeeper
dataLogDir=/var/lib/log
clientPort=
2181
initLimit=
5
syncLimit=
2
server.
1
=IP1:
2888
:
3888
server.
2
=IP2:
2888
:
3888
server.
3
=IP3:
2888
:
3888
可以看到,比较于单机模式,集群模式多了 server.id=host:port1:port2的配置。
个中,id 被称为 Server ID,用来标识该机器在集群中的机器序号(在每台机器的 dataDir 目录下创建 myid 文件,文件内容即为该机器对应的 Server ID 数字)。host 为机器 IP,port1用于指定 Follower 做事器与 Leader 做事器进行通信和数据同步的端口,port2用于进行 Leader 选举过程中的投票通信。
4. 创建 myid 文件
在 dataDir 目录下创建名为 myid 的文件,在文件第一行写上对应的 Server ID。
5. 按照相同步骤,为其他机器配置 zoo.cfg 和 myid文件6. 启动做事1.3 伪集群模式
这是一种分外的集群模式,即集群的所有做事器都支配在一台机器上。当你手头上有一台比较好的机器,如果作为单机模式进行支配,就会摧残浪费蹂躏资源,这种情形下,ZooKeeper许可你在一台机器上通过启动不同的端口来启动多个 ZooKeeper 做事实例,以此来以集群的特性来对外做事。
这种模式下,只须要把 zoo.cfg 做如下修正:
1
2
3
4
5
6
7
8
9
tickTime=
2000
dataDir=/var/lib/zookeeper
dataLogDir=/var/lib/log
clientPort=
2181
initLimit=
5
syncLimit=
2
server.
1
=IP1:
2888
:
3888
server.
2
=IP1:
2889
:
3889
server.
3
=IP1:
2890
:
3890
二、集群组成
要搭建一个高可用的 ZooKeeper 集群,我们首先须要确定好集群的规模。
关于 ZooKeeper 集群的做事器组成,相信很多对 ZooKeeper 理解但是理解不足深入的读者,都存在或曾经存在过这样一个缺点的认识:为了使得 ZooKeeper 集群能够顺利地选举出 Leader,必须将 ZooKeeper 集群的做事器数支配成奇数。这里我们须要澄清的一点是:任意台 ZooKeeper 做事器都能支配且能正常运行。
那么存在于这么多读者中的这个缺点认识是怎么回事呢?实在关于 ZooKeeper 集群做事器数,ZooKeeper 官方确实给出了关于奇数的建议,但绝大部分 ZooKeeper 用户对付这个建议认识有偏差。在本书前面提到的“过半存活即可用”特性中,我们已经理解了,一个 ZooKeeper 集群如果要对外供应可用的做事,那么集群中必须要有过半的机器正常事情并且彼此之间能够正常通信。基于这个特性,如果想搭建一个能够许可 N 台机器 down 掉的集群,那么就要支配一个由 2N+1 台做事器构成的 ZooKeeper 集群。因此,一个由 3 台机器构成的 ZooKeeper 集群,能够在挂掉 1 台机器后依然正常事情,而对付一个由 5 台做事器构成的 ZooKeeper 集群,能够对 2 台机器挂掉的情形进行容灾。把稳,如果是一个由6台做事器构成的 ZooKeeper 集群,同样只能够挂掉 2 台机器,由于如果挂掉 3 台,剩下的机器就无法实现过半了。
因此,从上面的讲解中,我们实在可以看出,对付一个由 6 台机器构成的 ZooKeeper 集群来说,和一个由 5 台机器构成的 ZooKeeper 集群,其在容灾能力上并没有任何显著的上风,反而多占用了一个做事器资源。基于这个缘故原由,ZooKeeper 集群常日设计支配成奇数台做事器即可。
三、容灾所谓容灾,在 IT 行业常日是指我们的打算机信息系统具有的一种在遭受诸如失火、地震、断电和其他根本网络设备故障等毁灭性灾害的时候,依然能够对外供应可用做事的能力。
对付一些普通的运用,为了达到容灾标准,常日我们会选择在多台机器上进行支配来组成一个集群,这样纵然在集群的一台或是多少台机器涌现故障的情形下,全体集群依然能够对外供应可用的做事。
而对付一些核心运用,不仅要通过利用多台机器构建集群的办法来供应做事,而且还要将集群中的机器支配在两个机房,这样的话,纵然个中一个机房遭遇灾害,依然能够对外供应可用的做事。
上面讲到的都是运用层面的容灾模式,那么对付 ZooKeeper 这种底层组件来说,如何进行容灾呢?讲到这里,可能多少读者会有疑问,ZooKeeper 既然已经办理了单点问题,那为什么还要进行容灾呢?
3.1 单点问题
单点问题是分布式环境中最常见也是最经典的问题之一,在很多分布式系统中都会存在这样的单点问题。
详细地说,单点问题是指在一个分布式系统中,如果某一个组件涌现故障就会引起全体系统的可用性大大低落乃至是处于瘫痪状态,那么我们就认为该组件存在单点问题。
ZooKeeper 确实已经很好地办理了单点问题。我们已经理解到,基于“过半”设计原则,ZooKeeper 在运行期间,集群中至少有过半的机器保存了最新的数据。因此,只要集群中超过半数的机器还能够正常事情,全体集群就能够对外供应做事。
3.2 容灾
办理了单点问题,是不是该考虑容灾了呢?答案是否定的,在搭建一个高可用的集群的时候依然须要考虑容灾问题。正如上面讲到的,如果集群中超过半数的机器还在正常事情,集群就能够对外供应正常的做事。
那么,如果全体机房涌现灾害性的事件,这时显然已经不是单点问题的范畴了。
在进行 ZooKeeper 的容灾方案设计过程中,我们要充分考虑到“过半原则”。也便是说,无论发生什么情形,我们必须担保 ZooKeeper 集群中有超过半数的机器能够正常事情。因此,常日有以下两种支配方案。
3.3.1 双机房支配
在进行容灾方案的设计时,我们常日因此机房为单位来考虑问题。在现实中,很多公司的机房规模并不大,因此双机房支配是个比较常见的方案。但是遗憾的是,在目前版本的 ZooKeeper 中,还没有办法能够在双机房条件下实现比较好的容灾效果——由于无论哪个机房发生非常情形,都有可能使得 ZooKeeper 集群中可用的机器无法超过半数。当然,在拥有两个机房的场景下,常日有一个机房是紧张机房(一样平常而言,公司会花费更多的钱去租用一个稳定性更好、设备更可靠的机房,这个机房便是紧张机房,而其余一个机房则更加廉价一些)。我们唯一能做的,便是只管即便在紧张机房支配更多的机器。例如,对付一个由 7 台机器组成的 ZooKeeper 集群,常日在紧张机房中支配 4 台机器,剩下的 3 台机器支配到其余一个机房中。
3.3.2 三机房支配
既然在双机房支配模式下并不能实现好的容灾效果,那么对付有条件的公司,选择三机房支配无疑是个更好的选择,无论哪个机房发生了故障,剩下两个机房的机器数量都超过半数。如果我们有三个机房可以支配做事,并且这三个机房间的网络状况良好,那么就可以在三个机房中都支配多少个机器来组成一个 ZooKeeper 集群。
我们假定构成 ZooKeeper 集群的机器总数为 N,在三个机房中支配的 ZooKeeper 做事器数分别为 N1、N2和 N3,如果要使该 ZooKeeper 集群具有较好的容灾能力,我们可以根据如下算法来打算 ZooKeeper 集群的机器支配方案。
1. 打算 N1
如果 ZooKeeper 集群的做事器总数是 N,那么:
1
N1 = (N-
1
)/
2
在 Java 中,“/” 运算符会自动对打算结果向下取整操作。举个例子,如果 N=8,那么 N1=3;如果 N=7,那么 N1也即是 3。
2. 打算 N2的可选值
N2的打算规则和 N1非常类似,只是 N2 的取值是在一个取值范围内:
1
N2 的取值范围是
1
~(N-N1)/
2
即如果 N=8,那么 N1=3,则 N2的取值范围便是 1~2,分别是 1 和 2。把稳,1 和 2 仅仅是 N2的可选值,并非终极值——如果 N2为某个可选值的时候,无法计算出 N3的值,那么该可选值也无效。
3. 打算 N3,同时确定 N2的值
很显然,现在只剩下 N3了,可以大略的认为 N3的取值便是剩下的机器数,即:
1
N3 = N - N1 - N2
只是 N3的取值必须知足 N3< N1+N2。在知足这个条件的根本下,我们遍历步骤 2 中计算得到的 N2的可选值,即可得到三机房支配时每个机房的做事器数量了。
现在我们以 7 台机器为例,来看看如何分配三机房的机器分布。根据算法的步骤 1,我们首先确定 N1的取值为 3。根据算法的步骤 2,我们确定了 N2的可选值为 1 和 2。末了根据步骤 3,我们遍历 N2的可选值,即可得到两种支配方案,分别是 (3,1,3) 和 (3,2,2)。以下是 Java 程序代码对以上算法的一种大略实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public
class
Allocation {
static
final
int
n =
7
;
public
static
void
main(String[] args){
int
n1,n2,n3;
n1 = (n-
1
) /
2
;
int
n2_max = (n-n1) /
2
;
for
(
int
i=
1
; i<=n2_max; i++){
n2 = i;
n3 = n - n1 -n2;
if
(n3 >= (n1+n2)){
continue
;
}
System.out.println(
\公众(\公众
+n1+
\"大众,\公众
+n2+
\公众,\"大众
+n3+
\"大众)\公众
);
}
}
}
四、水平扩容
水平可扩容可以说是对一个分布式系统在高可用性方面提出的基本的,也是非常主要的一个哀求,通过水平扩容能够帮助系统在不进行或进行极少改进事情的条件下,快速提高系统对外的做事支撑能力。大略地讲,水平扩容便是向集群中添加更多的机器,以提高系统的做事质量。
很遗憾的是,ZooKeeper 在水平扩容扩容方面做得并不十分完美,须要进行全体集群的重启。常日有两种重启办法,一种是集群整体重启,其余一种是逐台进行做事器的重启。
4.1 整体重启
所谓集群整体重启,便是先将全体集群停滞,然后更新 ZooKeeper 的配置,然后再次启动。如果在你的系统中,ZooKeeper 并不是个非常核心的组件,并且能够许可短暂的做事停滞(常日是几秒钟的韶光间隔),那么不妨选择这种办法。在整体重启的过程中,所有该集群的客户端都无法连接上集群。等到集群再次启动,这些客户端就能够自动连接上——把稳,整体启动前建立起的客户端会话,并不会由于这次整体重启而失落效。也便是说,在整体重启期间花费的韶光将不计入会话超时时间的打算中。
4.2 逐台重启
这种办法更适宜绝大多数的实际场景。在这种办法中,每次仅仅重启集群中的一台机器,然后逐台对全体集群中的机器进行重启操作。这种办法可以在重启期间依然担保集群对外的正常做事。
参考文章:《从Paxos到Zookeeper 分布式同等性事理与实践》
作者:cyfonly
出处:http://www.cnblogs.com/cyfonly/
Java高等架构∣干货|互换
长按,识别二维码,加关注