Zookeeper 3.5+提供了reconfig功能实现动态配置节点,官方的说明是,“你再也不需要进行全部节点重启”就可以应用所有的修改:

http://zookeeper.apache.org/doc/r3.5.4-beta/zookeeperReconfig.html

我们不妨按照官方的说明尝试一下。

 

根据文档,我们先配置一个3节点集群好了,配置文件内容如下:

 

zoo1.cfg

reconfigEnabled=true
standaloneEnabled=false
tickTime=2000
dataDir=/tmp/zkcluster/zk1
initLimit=5
syncLimit=2
clientPort=2791
server.1=127.0.0.1:2780:2783:participant;2791
server.2=127.0.0.1:2781:2784:participant;2792
server.3=127.0.0.1:2782:2785:participant;2793

 

zoo2.cfg

reconfigEnabled=true
standaloneEnabled=false
tickTime=2000
dataDir=/tmp/zkcluster/zk2
initLimit=5
syncLimit=2
clientPort=2792
server.1=127.0.0.1:2780:2783:participant;2791
server.2=127.0.0.1:2781:2784:participant;2792
server.3=127.0.0.1:2782:2785:participant;2793

 

zoo3.cfg

reconfigEnabled=true
standaloneEnabled=false
tickTime=2000
dataDir=/tmp/zkcluster/zk3
initLimit=5
syncLimit=2
clientPort=2793
server.1=127.0.0.1:2780:2783:participant;2791
server.2=127.0.0.1:2781:2784:participant;2792
server.3=127.0.0.1:2782:2785:participant;2793

 

其实这三个配置文件基本相同,差别就是dataDir和clientPort不同。

请注意如下几点:

1. reconfigEnabled=true,这个配置是用来实现动态配置的,一定要设置,否则集群启动后会无法修改现有配置

2. standaloneEnabled=false,根据官方文档:

http://zookeeper.apache.org/doc/r3.5.4-beta/zookeeperReconfig.html#sc_reconfig_standaloneEnabled

的"The standaloneEnabled flag"章节,文中提到的:

Prior to 3.5.0, one could run ZooKeeper in Standalone mode or in a Distributed mode. These are separate implementation stacks, and switching between them during run time is not possible. By default (for backward compatibility) standaloneEnabled is set to true. The consequence of using this default is that if started with a single server the ensemble will not be allowed to grow, and if started with more than one server it will not be allowed to shrink to contain fewer than two participants.

Setting the flag to false instructs the system to run the Distributed software stack even if there is only a single participant in the ensemble. To achieve this the (static) configuration file should contain:

standaloneEnabled=false

 因为Standalone和Ensemble模式使用的是不同的实现栈,为了让我们的集群能够动态增加和减少节点,并且集群节点能够少于2,最好使用Ensemble模式。

3. clientPort=2793, 官方文档不建议使用这个参数,但是我实在不知道如何配置连接用的端口,所以保留了这个参数

4. dataDir, 请为每个节点单独配置一个数据目录,且里面建立一个名为“myid”的文件,内容为本节点的id(例如dataDir=/tmp/zkcluster/zk1的节点,在此目录创建myid文件,内容为1)。这个目录会存放集群数据的快照。

 

当我们设置好上述参数后,即可启动节点:

zookeeper临时节点创建_zookeeper

上图中,我写了个脚本能够只要输入节点的编号即可启动,实际上执行时,请使用:

zkServer.sh start /dir/to/zookeeper/conf/zooN.cfg

启动

 

此时我们连上任何一个节点,可以看到集群已经启动了:

zkCli.sh -server 127.0.0.1:2791

连上集群后使用config命令检查节点:

zookeeper临时节点创建_ci_02

 

至此为止都是基本操作,接下来到达最重要的部分:动态配置集群以实现增加或者减少节点

首先我们以下述配置文件再启动一个节点:

reconfigEnabled=true
standaloneEnabled=false
tickTime=2000
dataDir=/tmp/zkcluster/zk4
initLimit=5
syncLimit=2
clientPort=2794
server.1=127.0.0.1:2780:2783:participant;2791
server.4=127.0.0.1:2801:2802:participant;2794

配置在前面的章节已经解释过了,但是配置节点时只设置了两个,这一点可能会令人迷惑,在这里说明一下:大家如果参考文档,会发现3.5+版本会自动把配置文件变为动态配置文件,静态的部分还是放在原来的zooN.cfg当中,动态的部分放到了zooN.cfg.dynamic.xxx当中了,而且集群的配置文件在绝大多数时间中都是一致的,只有在重新配置的时候会经历短暂的不一致,利用这一特性,让新加入节点连接到集群上,然后从集群同步配置过来即可。

启动这个节点后,连接上这个节点观察集群:

zookeeper临时节点创建_zookeeper_03

大家可以看到,这个节点实际上是连接到集群的,但是从集群上同步的配置却不包含本节点。

注意:前面提到过自动同步配置的机制,此时本节点(节点4)会将集群配置同步到本地,如果此时重启节点,节点将没有办法再次被启动,因为集群中不包含本节点。

 

现在连接到任何一个集群内节点(1,2,或者3),使用下述命令添加节点:

reconfig -add server.4=127.0.0.1:2801:2802:participant;2794

然后就。。。。。失败了

zookeeper临时节点创建_配置文件_04


zookeeper临时节点创建_zookeeper_05

搜索一下Authentication is not valid,可以知道是因为服务器默认没有/zookeeper/config的写入权限导致的,此时需要添加写入权限:

1. 先进入zookeeper的安装目录,然后执行下述命令产生认证使用的摘要信息:

java -cp ./lib/*:./* org.apache.zookeeper.server.auth.DigestAuthenticationProvider su:passwd

说明下,这条命令实际上在执行zookeeper的org.apache.zookeeper.server.auth.DigestAuthenticationProvider功能,

使用用户名:su

和密码:passwd

产生认证参数,执行完毕后程序返回:

su:passwd->su:gACzJ4L2A0F2ygTno5HQnfabuik=

2. 修改zkServer.sh,添加下述命令行:

SERVER_JVMFLAGS="-Dzookeeper.DigestAuthenticationProvider.superDigest=su:gACzJ4L2A0F2ygTno5HQnfabuik="

其中红色部分是上一步(1)产生的摘要信息。

然后重启集群中的一个节点

3. 连接步骤2中重启的节点,执行下述命令:

addauth digest su:passwd
reconfig -add server.4=127.0.0.1:2801:2802:participant;2794

结果如图:

zookeeper临时节点创建_zookeeper临时节点创建_06

 

此时我们连接到第四个节点,然后通过config检查:

zookeeper临时节点创建_配置文件_07

发现第四个节点确实已经在集群中了,图中我还在第四个节点get了一下/k的值,这个值是在第一个节点设置的,可以看到,数据也同步过来了。

终于用上了zookeeper的动态配置功能,再也不用一个一个重启实例来添加集群节点了

zookeeper临时节点创建_ci_08

 

最后,关于zookeeper集群的几点思考:

1. 在整个集群中,保留几个节点作为核心集群,当要添加、删除节点时,从这些节点进行,这样就不需要为所有的节点都提供/zookeeper/config的写入权限,在生产环境中要是每个节点都获取了写入权限,很有可能导致非专职运维的成员能够修改集群信息。当然,最重要的还是密码的保护,要是密码被非运维人员知道了,同时他也知道核心节点的地址,一样可以修改集群配置。

 

2. 关于集群节点数量的问题,上面的例子中,我们向3节点的集群增加了一个节点,这只是一个说明动态配置zookeeper的例子,实际使用时集群节点数量最好为奇数,因为zookeeper是基于大多数节点可用时集群可用的,也就是说,当有5个节点时,可以容忍2个节点的失效,而当拥有4个节点时,只能容忍一个节点失效,和拥有3个节点效果一样。


“Designing a ZooKeeper Deployment”章节的“Cross Machine Requirements”中,有集群中节点数量的计算公式:

2xF+1

其中F是集群容忍失效机器的数目,通过这个公式计算,3个节点的集群和4个节点的集群都只能容忍1个节点的失效

 

3. 关于动态向集群添加节点


1. 通过配置文件将要添加的节点当作Observer加入集群(可以添加多个节点),然后再在系统中重新配置为Participant

2. 通过配置文件将要添加的节点当作Participant加入集群,每个节点的配置文件只能添加集群节点和自己,否则新加入的节点可能形成一个集群,导致发生脑裂,请参考下面的“Warning”部分

3. 仅将Leader节点和自己加入配置文件,然后通过reconfig将自身加入集群(本实例中使用的方法),这种方法有两个前提条件:

a. 配置文件中只能出现自身节点和Leader节点

b. 如果添加节点的过程中Leader挂掉,此时自身的配置已经有问题了,需要下线本节点重新配置再加入

实际生产时,使用1是最可靠的。