基于zookeeper实现配置中心功能的简单工程

回眸只為那壹抹淺笑 提交于 2020-02-15 08:07:27

上一篇文章说到了一些zookeeper的应用场景,本篇将是对这些场景进行代码模拟实战的开篇文章。之前已经在本地搭建起了zk集群,并进行了一些api实践,因此本章主要讲述如何使用zk客户端模拟一个配置中心,推送变更的场景。

初始化配置bean

package com.coderman.zookeeper.clusterdemo.configdemo;

import java.io.Serializable;

/**
 * @description:
 * @author: Fanchunshuai
 * @time: 2020/2/13 15:04
 * zookeeper目录规则:/group/ip/appName
 * 这里的对象需要实现序列化
 */
public class ServerConfigBean implements Serializable {
    /**
     * 集群节点目录一级分组
     */
    private String group;
    /**
     * 集群节点数据内容
     */
    private String nodeData;
    /**
     * 集群ip
     */
    private String ip;
    /**
     * 集群中的应用名称
     */
    private String appName;


    public String getGroup() {
        return group;
    }

    public void setGroup(String group) {
        this.group = group;
    }

    public String getNodeData() {
        return nodeData;
    }

    public void setNodeData(String nodeData) {
        this.nodeData = nodeData;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getAppName() {
        return appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }

    @Override
    public String toString() {
        return "ServerConfigBean{" +
                "group='" + group + '\'' +
                ", nodeData='" + nodeData + '\'' +
                ", ip='" + ip + '\'' +
                ", appName='" + appName + '\'' +
                '}';
    }
}

构建配置管理器

package com.coderman.zookeeper.clusterdemo.configdemo;

import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;

/**
 * @description:
 * @author: Fanchunshuai
 * @time: 2020/2/14 15:45
 * 配置管理器
 */
public class ConfigManager {
    private static StringBuffer buffer = new StringBuffer();
    private static final int CONNECT_TIMEOUT = 5000;

    static {
        buffer.append("192.168.1.8:2184,");
        buffer.append("192.168.1.8:2181,");
        buffer.append("192.168.1.8:2182,");
        buffer.append("192.168.1.8:2183,");
        buffer.append("192.168.1.8:2185");
    }

    /**
     * 初始化数据
     * 一般需要将配置文件从配置管理平台导入到zookeeper集群,或者从别的文件等来源将配置数据持久化到zk
     *
     * @return
     */
    public ServerConfigBean getServerConfigBeanFromDB(){
        ServerConfigBean serverConfigBean = new ServerConfigBean();
        serverConfigBean.setAppName("app1");
        serverConfigBean.setIp("10.0.0.1");
        serverConfigBean.setNodeData("a,b,b,c,d");
        serverConfigBean.setGroup("b2bgroup");
        return serverConfigBean;
    }

    /**
     * 第一次初始化数据节点,并将配置文件数据同步到zookeeper中
     * 这里相当于服务端的服务接口
     */
    public void syncConfigToZookeeper(ServerConfigBean serverConfigBean){
        ZkClient zkClient = new ZkClient(buffer.toString(),CONNECT_TIMEOUT);
        String path = "/"+serverConfigBean.getGroup()+"/"+serverConfigBean.getIp()+"/"+serverConfigBean.getAppName();
        if(!zkClient.exists(path)){
            //递归创建持久节点
            zkClient.createPersistent(path,true);
            zkClient.writeData(path,serverConfigBean);
        }
        zkClient.close();
    }

    /**
     * 更新配置到zookeeper集群
     * 这里相当于服务端的服务接口
     * @param serverConfigBean
     */
    public void updateConfigToZookeeper(ServerConfigBean serverConfigBean){
        ZkClient zkClient = new ZkClient(buffer.toString(),CONNECT_TIMEOUT);
        String path = "/"+serverConfigBean.getGroup()+"/"+serverConfigBean.getIp()+"/"+serverConfigBean.getAppName();
        zkClient.writeData(path,serverConfigBean);
        zkClient.close();
    }


    /**
     * 从zookeeper集群中获取数据配置
     * 这里相当于客户端的服务接口
     * @return
     */
    public ServerConfigBean getConfigFromZookeeper(ServerConfigBean serverConfigBean){
        ZkClient zkClient = new ZkClient(buffer.toString(),CONNECT_TIMEOUT);
        final ServerConfigBean[] serverConfigBeanx = {serverConfigBean};
        String path = getPath(serverConfigBean);
        //先读取数据
        serverConfigBeanx[0] = zkClient.readData(path);
        zkClient.subscribeDataChanges(path,new IZkDataListener (){
            @Override
            public void handleDataChange(String s, Object o) throws Exception {
                System.out.println("config data changed = "+s);
                //如果数据有变化则更新
                serverConfigBeanx[0] = (ServerConfigBean)o;
                System.out.println( serverConfigBeanx[0].toString());
            }

            @Override
            public void handleDataDeleted(String s) throws Exception {
                System.out.println("config data deleted = "+s);
            }
        });
        return serverConfigBeanx[0];
    }

    private String getPath (ServerConfigBean serverConfigBean){
        return "/"+serverConfigBean.getGroup()+"/"+serverConfigBean.getIp()+"/"+serverConfigBean.getAppName();
    }

}

演示主代码

package com.coderman.zookeeper.clusterdemo.configdemo;

import com.alibaba.fastjson.JSON;

/**
 * @description:
 * @author: Fanchunshuai
 * @time: 2020/2/14 16:16
 * 配置中心变更演示案例
 */
public class ConfigChangeDemo {
    public static void main(String[] args) {
        ConfigManager configManager = new ConfigManager();
        ServerConfigBean serverConfigBean = configManager.getServerConfigBeanFromDB();
        configManager.syncConfigToZookeeper(serverConfigBean);

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        ServerConfigBean serverConfigBean1 = configManager.getConfigFromZookeeper(serverConfigBean);
        System.out.println(JSON.toJSONString(serverConfigBean1));

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //更新数据
        serverConfigBean1.setNodeData("sdfasdfasdfasdf");
        //重新同步
        configManager.updateConfigToZookeeper(serverConfigBean1);
        //重新获取数据
        ServerConfigBean serverConfigBean2 = configManager.getConfigFromZookeeper(serverConfigBean);
        System.out.println(JSON.toJSONString(serverConfigBean2));

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //多线程更新,查看数据监听变化
        //这里的线程其实就是数据操作变更的客户端

        new Thread(()->{
            //更新数据
            serverConfigBean1.setNodeData("sdfasdfasddddfasdf");
            //重新同步
            configManager.updateConfigToZookeeper(serverConfigBean1);
            ServerConfigBean serverConfigBean3 = configManager.getConfigFromZookeeper(serverConfigBean);
            System.out.println("serverConfigBean3 = "+JSON.toJSONString(serverConfigBean3));

        },"thread1").start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            //更新数据
            serverConfigBean1.setNodeData("sddfasdf");
            //重新同步
            configManager.updateConfigToZookeeper(serverConfigBean1);
            ServerConfigBean serverConfigBean4 = configManager.getConfigFromZookeeper(serverConfigBean);
            System.out.println("serverConfigBean4 = "+JSON.toJSONString(serverConfigBean4));

        },"thread2").start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            //更新数据
            serverConfigBean1.setNodeData("sdfasdfasddddddddfasdf");
            //重新同步
            configManager.syncConfigToZookeeper(serverConfigBean1);
            ServerConfigBean serverConfigBean5 = configManager.getConfigFromZookeeper(serverConfigBean);
            System.out.println("serverConfigBean5 = "+JSON.toJSONString(serverConfigBean5));

        },"thread3").start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

总结:
zookeeper实现分布式配置服务推送的主要角色有
1.zookeeper集群,相当于存储配置数据的容器
2.zookeeper管理平台,相当于管理平台提供对数据增,删,改的服务接口或者可视化界面,数据源可以是手动输入的也可以是从其他系统或文件中导入获取的。
3.zookeeper的应用客户端,比如我有一个app服务器,服务器端也需要连接zookeeper集群,监听节点变化,由于配置可能随时更新,因此应用客户端捕获到内容变化之后需要更新配置。
如果想要做的更丰富的话,就需要有下面的辅助设施
1.监控:监控zk心跳,zk集群等数据容量,数据延迟等
2.审批:节点审批,数据变更审批
相关链接:
https://www.cnblogs.com/hujunzheng/p/10932153.html

这里仅仅进行了简单的模拟知道怎么回事,需要怎么弄,如果想要做到可以生产环境使用还需要做更多内容。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!