动态配置
Zookeeper 3.5.0 以前,Zookeeper集群角色要发生改变的话,只能通过停掉所有的Zookeeper服务,修改集群配置,重启服务来完成,这样集群服务将有一段不可用的状态,为了应对高可用需求,Zookeeper 3.5.0 提供了支持动态扩容/缩容的 新特性。但是通过客户端API可以变更服务端集群状态是件很危险的事情,所以在zookeeper 3.5.3 版本要用动态配置,需要开启超级管理员身份验证模式 ACLs。如果是在一个安全的环境也可以通过配置 系统参数 -Dzookeeper.skipACL=yes 来避免配置维护acl 权限配置。
添加超级管理员授权
先配置一个超级管理员(如果不配管理员,也可以设置系统参数 -Dzookeeper.skipACL=yes):如:
在zookeeper启动脚本中添加 超级管理员授权模式:
echo -n zookeeper:123 | openssl dgst -binary -sha1 | openssl base64
# RRCKWv2U2e99M6UmsFaJiQ2xStw=
# 在 zkServer.sh 的 ZOOMAIN 中添加如下配置
-Dzookeeper.DigestAuthenticationProvider.superDigest=zookeeper:RRCKWv2U2e99M6UmsFaJiQ2xStw=
修改配置文件
修改原集群配置文件 zoo1.cfg/zoo2.cfg/zoo3.cfg
- 移除 clientPort 配置
- 移除 集群 server.x 配置
- 添加 reconfigEnabled 配置, 设置为true 开启动态配置
- 添加 dynamicConfigFile 配置, 指定动态配置文件的路径, 如 /application/zookeeper-3.5.8/mrathena/dynamic.config
添加动态配置文件
添加 zoo1.cfg.dynamic/zoo2.cfg.dynamic/zoo3.cfg.dynamic 3个动态配置文件, 内容是集群信息
# server.A=B.C.D.E;F
# A: 服务的唯一标识, B: 服务对应的IP地址, 集群通信端口, 集群选举端口
# E: 角色, 默认是 participant, 即参与过半机制的角色,选举,事务请求过半提交,还有一个是observer, 观察者,不参与选举以及过半机制。
# F: 服务IP:端口, 注意 E 和 F 之间的是 分号 ;
server.1=172.16.138.202:3281:4281:participant;172.16.138.202:2281
server.2=172.16.138.202:3282:4282:participant;172.16.138.202:2282
server.3=172.16.138.202:3283:4283:participant;172.16.138.202:2283
server.4=172.16.138.202:3284:4284:observer;172.16.138.202:2284
客户端操作
依次启动服务, 连接任一台服务
# 查看集群配置
config
get /zookeeper/config
# 如果要修改集群状态, 需要授权登录
addauth digest zookeeper:123
# 移除serverId为 3 的机器
reconfig -remove 3
# 把对应的机器加进来
reconfig -add server.3=172.16.138.202:3283:4283:participant;172.16.138.202:2283
如果要变更/或者添加新的服务需要将服务加到配置文件 zoo_replicated1.cfg.dynamic 中,启动服务, 然后通过 reconfig 命令进行添加或者变更服务角色,但是需要保证服务列表中 participant 角色能够形成集群(过半机制)。
代码操作
客户端可以通过监听 /zookeeper/confg 节点,来感知集群的变化。从而实现集群的动态变更.
Zookeeper 类提供了对应的API 用来更新服务列表 : updateServerList
Watcher watcher = new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.None && event.getState() == Event.KeeperState.SyncConnected){
countDownLatch.countDown();
log.info(" 连接建立");
// start to watch config
try {
log.info(" 开始监听:{}",ZooDefs.CONFIG_NODE);
zookeeper.getConfig(true,null);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if( event.getPath()!=null && event.getPath().equals(ZooDefs.CONFIG_NODE)){
try {
byte[] config = zookeeper.getConfig(this, null);
String clientConfigStr = ConfigUtils.getClientConfigStr(new String(config));
log.info(" 配置发生变更: {}",clientConfigStr);
zookeeper.updateServerList(clientConfigStr.split(" ")[1]);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
Apache Curator 也自带了动态配置的监听,不需要额外的配置和代码实现监听更新