zookeeper09-重配置ZooKeeper

1、为什么不能使用简单的扩容

  • 现在有三台机器组成的ZooKeeper集群。但是一两个月后,你会发现使用ZooKeeper的客户端越来越多,并且成为一个关键的服务,因此你想要把服务器扩容到五台,没什么大不了的,是嘛?你可以在深夜停止集群,重新配置所有服务器,并在不到一分钟的时间里恢复服务。如果你的应用程序恰当处理了Disconnected事件,用户可能不会感知到服务中断。我们在刚开始开发ZooKeeper时也是这么想的,但事实证明,情况要复杂得多。
  • 请看图10-1中的场景,三个服务器(A、B、C)组成的集群。服务器C因网络拥塞稍稍落后于整个集群,因此服务器C刚刚了解事务到(1,3)(其中1为时间戳,3为对应该时间戳的事务标识)。因为服务器A和B的通信良好,所以服务器C稍稍落后并不会导致整个系统变慢,因此服务器A和B已经提交事务到(1,6)。

  • 现在,假设我们将所有zookeeper服务停止,把服务器D和E添加到集群中,当然这两台新服务器并不存在任何状态信息。我们重新配置A、B、C、D和E服务器,使它们成为一个更大的集群,然后重新启动服务。因为我们现在有五台服务器,因此至少需要三台服务器组成法定人数。C、D和E三台服务器就能够构成法定人数,因此当这些服务器(图10-2)构成法定人数并开始同步时会发生什么。这个场景可以简单实现,比如让A和B比其他三个服务器晚启动一些。一旦新的法定人数开始同步,服务器D和E就会与服务器C进行同步,因为法定人数中服务器C的状态为最新状态,法定人数的三个成员服务器会同步到最后的事务(1,3),而不会同步(1,4)、(1,5)和(1,6)这三个事务,因为服务器A和B并不是构成法定人数的成员。

  • 因为C、D和E三台服务器已经构成一个活跃的法定人数,这些服务器可以开始提交新事务。我们假设有两个事务:(2,1)和(2,2)。如图10-3所示,当服务器A和B启动后连接到服务器C后,服务器C作为leader欢迎它们加入到集群中,并在收到事务(2,1)和(2,2)后,立即告知服务器A和B删除事务(1,4)、(1,5)和(1,6)。

  • 这个结果非常糟糕,我们丢失了某些状态信息,而且状态副本与客户端所看到的(1,4)、(1,5)、(1,6)也不再一致。为了避免这个问题,ZooKeeper提供了重配置操作,这意味着运维人员并不需要手工进行重配置操作,也不会破坏状态,而且也不需要停止任何服务。

2、ZooKeeper的重配置

  • 重配置不仅可以让我们改变集群成员配置,还可以修改网络参数配置。因为ZooKeeper中配置信息的变化,需要将重配置参数与静态的配置文件分离,并将其单独保存为一个配置文件(reconfig命令会自动更新该文件)。dynamicConfigFile参数将两个文件链接在一起
  • 我们现在有一个有三台服务器组成的ZooKeeper集群,每台ZooKeeper服务器的配置如下:
]# cat /usr/local/apache-zookeeper-3.5.9-bin/conf/zoo.cfg
#ZooKeeper服务法心跳时间,单位为ms
tickTime=2000
#投票选举新leader的初始化时间
initLimit=10
#leader与follower心跳检测最大容忍时间,响应超过syncLimit*tickTime,leader认为follower“死掉”,从服务器列表中删除follower
syncLimit=5
#ZooKeeper对外服务端口
clientPort=2181
#快照目录
dataDir=/tmp/zookeeper/data
#事务日志目录
dataLogDir=/tmp/zookeeper/log
#ZooKeeper集群中服务器的列表    --和独立模式不同的地方,
server.1=10.1.1.11:2888:3888
server.2=10.1.1.12:2888:3888
server.3=10.1.1.13:2888:3888
#允许执行reconfig命令
reconfigEnabled=true
#允许执行四字母命令
4lw.commands.whitelist=*
#禁止leader为客户端提供服务
leaderServes=no
  • 启动服务后,配置文件变成两个文件,如下:
]# cat /usr/local/apache-zookeeper-3.5.9-bin/conf/zoo.cfg
initLimit=10
syncLimit=5
leaderServes=no
4lw.commands.whitelist=*
clientPort=2181
tickTime=2000
dataDir=/tmp/zookeeper/data
reconfigEnabled=true
dataLogDir=/tmp/zookeeper/log
dynamicConfigFile=/usr/local/apache-zookeeper-3.5.9-bin/conf/zoo.cfg.dynamic.100000000

]# cat /usr/local/apache-zookeeper-3.5.9-bin/conf/zoo.cfg.dynamic.100000000
server.1=10.1.1.11:2888:3888:participant
server.2=10.1.1.12:2888:3888:participant
server.3=10.1.1.13:2888:3888:participant
  • 注意,zoo.cfg.dynamic.100000000文件只由服务器条目组成,每个条目都是一样的(可以从配置文件中删除clientPort参数):
    • server.id=host:n:n[:role];[client_address:]client_port
    • 与正常的配置文件一样,每个服务器都列出了主机名和分别用于仲裁、leader选举的端口号。
    • role:其值必须为participant或observer。默认值是participant。
    • client_port:服务器监听的端口,用于客户端连接的服务器端口号。
    • client_address:绑定服务器的特定网络接口地址。
  • 修改zoo.cfg文件,并分发到所有的ZooKeeper服务器上
--删除了clientPort参数
]# vim /usr/local/apache-zookeeper-3.5.9-bin/conf/zoo.cfg
initLimit=10
syncLimit=5
leaderServes=no
4lw.commands.whitelist=*
tickTime=2000
dataDir=/tmp/zookeeper/data
reconfigEnabled=true
dataLogDir=/tmp/zookeeper/log
dynamicConfigFile=/usr/local/apache-zookeeper-3.5.9-bin/conf/zoo.cfg.dynamic.100000000

--将zoo.cfg文件分发到所有服务器上
]# scp /usr/local/apache-zookeeper-3.5.9-bin/conf/zoo.cfg root@10.1.1.12:/usr/local/apache-zookeeper-3.5.9-bin/conf/
  • 配置新的ZooKeeper服务器,并启动。
--有两台新的服务器10.1.1.14和10.1.1.15,以10.1.1.14为例
]# vim /usr/local/apache-zookeeper-3.5.9-bin/conf/zoo.cfg.dynamic.100000000    --不加11、12、13条目重配置时,14机器不能加入集群。不加14条目,14机器上的服务不能启动(必须带端口)
server.1=10.1.1.11:2888:3888:participant
server.2=10.1.1.12:2888:3888:participant
server.3=10.1.1.13:2888:3888:participant
server.4=10.1.1.14:2888:3888:participant;0.0.0.0:2181

]# mkdir -p /tmp/zookeeper/{data,log}
]# echo '4' > /tmp/zookeeper/data/myid

]# zkServer.sh start
  • 现在,我们就可以通过reconfg操作来重新配置一个集群,可以增量或全量(整体)地进行更新操作。

1、增量重配置

  • 增量的重配置操作有两个列表:待删除的服务器列表待添加的服务器项的列表。待删除的服务器列表仅是使用逗号分隔的服务器ID列表,待添加的服务器项列表是使用逗号分隔的服务器项列表,每个服务器项的形式为动态配置文件中所定义的形式。例如:
--使用超级管理员
[zk: localhost:2181(CONNECTED) 0] addauth digest super:asdf
--查看当前集群信息
[zk: localhost:2181(CONNECTED) 1] config
server.1=10.1.1.11:2888:3888:participant
server.2=10.1.1.12:2888:3888:participant
server.3=10.1.1.13:2888:3888:participant
version=100000000
--将4、5加入到集群
[zk: localhost:2181(CONNECTED) 2] reconfig -add server.4=10.1.1.14:2888:3888:participant;2181,server.5=10.1.1.15:2888:3888:participant;2181
Committed new configuration:
server.1=10.1.1.11:2888:3888:participant
server.2=10.1.1.12:2888:3888:participant
server.3=10.1.1.13:2888:3888:participant
server.4=10.1.1.14:2888:3888:participant;0.0.0.0:2181
server.5=10.1.1.15:2888:3888:participant;0.0.0.0:2181
version=10000000d

2、全量重配置

[zk: localhost:2181(CONNECTED) 2] reconfig -members server.1=10.1.1.11:2888:3888:participant;0.0.0.0:2181,server.2=10.1.1.12:2888:3888:participant;0.0.0.0:2181,server.4=10.1.1.14:2888:3888:participant;0.0.0.0:2181,server.5=10.1.1.15:2888:3888:participant;0.0.0.0:2181

[zk: localhost:2181(CONNECTED) 2] config
server.1=10.1.1.11:2888:3888:participant;0.0.0.0:2181
server.2=10.1.1.12:2888:3888:participant;0.0.0.0:2181
server.4=10.1.1.14:2888:3888:participant;0.0.0.0:2181
server.5=10.1.1.15:2888:3888:participant;0.0.0.0:2181
version=10000001e

3、使用文件进行重配置

  • 我们还可以使用-file参数来指定一个新的成员配置文件来进行一次全量更新。例如:reconfig -file newconf命令会产生如上面命令一样的增量操作结果, newcon文件为:
server.1=10.1.1.10:1188:1288:participant;2181
server.4=10.1.1.14:4188:4288:participant;2184
server.5=10.1.1.15:5188:5288:participant;2185
  • 最后,所有形式的reconfig都可以是有条件的。如果通过-v参数提供了配置版本号,reconfig命令会在执行前确认配置文件当前的版本号是否匹配,只有匹配才会成功执行。你可以通过读取/zookeeper/config来获取当前配置的版本号,或通过zkCli工具来调用config获取配置版本号信息。 
[zk: localhost:2181(CONNECTED) 0] get /zookeeper/config 
server.1=10.1.1.10:2888:3888:participant
server.2=10.1.1.11:2888:3888:participant
server.3=10.1.1.12:2888:3888:participant
version=0

3、管理客户端的连接串

  • 我们已经讨论了ZooKeeper服务器配置,但是客户端也有一些相关的配置:连接串。客户端连接串通常表示为由逗号分隔的host:port对,其中host为主机名或IP地址。使用主机名可以在服务器的实际IP地址和用于访问服务器的标识符之间建立一个间接层。例如,运维人员可以替换ZooKeeper服务为另一个,而不需要改变客户端的配置。
  • 不过,这种灵活性有一定限制,运维人员可以改变组成集群的服务器机器,但不能改变客户端正在使用的服务器。例如,如图10-4所示,ZooKeeper可以通过重配置很简单地将集群从三个服务器扩展到五个服务器,但客户端仍然使用三个服务器,而不是五个。

  • 还有一种方法可以在不改变客户端配置的情况下,使ZooKeeper在服务器数量方面更具弹性。一个主机名解析为单个IP地址是很自然的,但实际上一个主机名可以解析为多个地址。如果一个主机名解析为多个IP地址, 客户端可以连接到其中任何一个IP地址。在图10-4中,假设服务器zk-a、zk-b和zk-c分别解析为三个独立的IP地址10.0.0.1、10.0.0.2和10.0.0.3。现在,假设您使用DNS配置一个主机名zk,并解析为这三个IP地址,你只需要修改DNS解析的地址数量,之后启动的任何客户端就可以访问这五个服务器,如图10-5所示。

  • 在使用主机名解析为多个地址方式时,有一些注意事项。首先,所有的服务器必须使用相同的端口号;其次,解析主机名只有在创建连接时才会发生,所以已经连接的客户端无法知道最新的名称解析,只能对新创建的客户端生效。
  • 客户端的连接还可以包含路径信息,此路径指示解析路径名时要使用的根路径,其行为类似于Unix中的chroot命令,而且在ZooKeeper社区中你也会经常听到人们以"chroot"来称呼这个功能。例如,如果客户端的连接串为zk:222/app/superApp,当客户端连接并执行getData("/a.dat",...)操作时,实际客户端会得到/app/superApp/a.dat节点的数据信息(注意,连接串中指示的路径必须存在,因为连接串不会为你创建该路径)
  • 在连接串中添加路径信息的动机在于一个ZooKeeper集群可以为多个应用程序提供服务,这样不需要要求每个应用程序添加其路径的前缀信息。每个应用程序都可以使用ZooKeeper,就像它是唯一使用集合的应用程序一样,运维人员可以按自己的意愿来划分命名空间。图10-6的示例展示了不同的连接串可以为客户端应用程序提供不同的名称空间。

  • 连接串的重叠
    • 当管理客户端连接串时,注意一个客户端的连接串永远不要包含两个不同的Zookeeper集群的主机名,这是导致脑裂最快速也是最简单方式。
posted @ 2022-02-01 23:21  麦恒  阅读(160)  评论(0编辑  收藏  举报