Zookeeper 3.5.0 新特性---集群动态配置
1、简介
Zookeeper 3.5.0 以前,Zookeeper集群角色要发生改变的话,只能通过停掉所有的 Zookeeper服务,修改集群配置,重启服务来完成,这样集群服务将有一段不可用的状态,为了 应对高可用需求,Zookeeper 3.5.0 提供了支持动态扩容/缩容的 新特性。但是通过客户端API 可以变更服务端集群状态是件很危险的事情,所以在zookeeper 3.5.3 版本要用动态配置,需要 开启超级管理员身份验证模式 ACLs。如果是在一个安全的环境也可以通过配置 系统参数 - Dzookeeper.skipACL=yes 来避免配置维护acl 权限配置。
2、集群动态配置
以下的每一个小标题就是一步:
2.1、配置一个超级管理员
如果不配管理员,也可以设置系统参数 - Dzookeeper.skipACL=yes,但是必须要保证在一个安全的环境下。
上面的操作都通过了,就说明超级管理员配置成功了
2.2、改造我们之前搭建的集群
依次按照下面方式,将每个服务的配置文件中的集群节点信息删掉,然后添加上下面两个配置
// 设置为true 开启动态配置
reconfigEnabled=true
// 指定动态配置文件的路径
dynamicConfigFile=/home/soft/zk/apache-zookeeper-3.7.0-bin/conf/zoo.cfg.dynamic
2.3、创建动态配置文件
在上面指定的路径下创建动态配置文件,并写入以下内容,保存即可。
server.1=192.168.231.131:2001:3001:participant;192.168.231.131:2181
server.2=192.168.231.131:2002:3002:participant;192.168.231.131:2182
server.3=192.168.231.131:2003:3003:participant;192.168.231.131:2183
server.4=192.168.231.131:2004:3004:observer;192.168.231.131:2184
2.4、依次启动4个服务
./zkServer.sh start ../conf/zoo1.cfg
2.5、连接服务器并查看状态
// 连接服务器
./zkCli.sh -server 192.168.231.131:2181,192.168.231.131:2182,192.168.231.131:2183,192.168.231.131:2184
// 查看集群状态
get /zookeeper/config
2.6、动态扩容
如果我们需要扩容集群,就可以登录超级管理员然后使用下面的命令
// 登录超级管理员
addauth digest super:paas
// 移除serverId为 3 的机器
reconfig ‐remove 3
// 把对应的机器加进来
reconfig ‐add server.3=192.168.231.131:2003:3003:participant;192.168.231.131:2183
3、用zk原生包来实现动态配置
其实说白了zk集群的动态配置也就是通过对 /zookeeper/config 这个节点的监听,动态刷新数据来实现的。
3.1、引入jar包
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.7.0</version>
</dependency>
3.2、实现类
public class ReconfigApp {
private final static String connectString = "192.168.231.131:2181,192.168.231.131:2182,192.168.231.131:2183,192.168.231.131:2184";
private static int SESSION_TIMEOUT=5* 1000;
private static CountDownLatch countDownLatch=new CountDownLatch(1);
private static ZooKeeper zookeeper =null;
private static Watcher watcher = new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.None
&& event.getState() == Event.KeeperState.SyncConnected){
countDownLatch.countDown();
System.out.println(" 连接建立");
// start to watch config
try {
System.out.println(" 开始监听:"+ 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));
System.out.println(" 配置发生变更: "+clientConfigStr);
zookeeper.updateServerList(clientConfigStr.split(" ")[1]);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
zookeeper = new ZooKeeper(connectString, SESSION_TIMEOUT, watcher);
countDownLatch.await();
Scanner scanner =new Scanner(System.in);
while (true){
byte[] data = zookeeper.getData("/zookeeper/config", true, null);
scanner.next();
System.out.println("DATA: "+new String(data));
}
}
}