• ZooKeeper配置管理文件


    最近在工作中,为了完善公司集群服务的架构,提高可用性,降低运维成本,因此开始学习ZooKeeper。
        至于什么是ZooKeeper?它能做什么?如何安装ZooKeeper?我就不一一介绍了,类似这些资料网上到处都是。我主要是把在开发过程中,以及个人对ZooKeeper的一些了解记录下来,大家如果遇到类似场景时,希望我的文章能够给你提供一些思路。

        我使用的ZooKeeper(以下简称:ZK)客户端是Curator Framework,是Apache的项目,它主要的功能是为ZK的客户端使用提供了高可用的封装。在Curator Framework基础上封装的curator-recipes,实现了很多经典场景。比如:集群管理(Leader选举)、共享锁、队列、Counter等等。可以总结Curator主要解决以下三类问题:

    • 封装ZK Client与Server之间的连接处理; 
    • 提供了一套Fluent风格的操作API; 
    • 提供ZK各种应用场景的抽象封装;

       本文主要完成的目标是:Spring PropertyPlaceholderConfigurer配置文件加载器集成ZooKeeper来实现远程配置读取。

        配置管理(Configuration Management)。
        在集群服务中,可能都会遇到一个问题:那就是当需要修改配置的时候,必须要对每个实例都进行修改,这是一个很繁琐的事情,并且易出错。当然可以使用脚本来解决,但这不是最好的解决办法。

    OK,Let's go!

    我们先看看项目结构

    ZooKeeperPropertyPlaceholderConfigurer.java

    继承org.springframework.beans.factory.config.PropertyPlaceholderConfigurer,重写processProperties(beanFactoryToProcess, props)来完成远端配置加载的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    package org.bigmouth.common.zookeeper.config.spring;
     
    import java.io.UnsupportedEncodingException;
    import java.util.Properties;
     
    import org.apache.commons.lang.StringUtils;
    import org.bigmouth.common.zookeeper.config.Config;
    import org.bigmouth.common.zookeeper.config.ZooKeeperConfig;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
     
     
    public class ZooKeeperPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
         
        public static final String PATH = "zoo.paths";
     
        @Override
        protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
                throws BeansException {
            super.processProperties(beanFactoryToProcess, props);
             
            try {
                fillCustomProperties(props);
                 
                System.out.println(props);
            }
            catch (Exception e) {
                // Ignore
                e.printStackTrace();
            }
        }
     
        private void fillCustomProperties(Properties props) throws Exception {
            byte[] data = getData(props);
            fillProperties(props, data);
        }
     
        private void fillProperties(Properties props, byte[] data) throws UnsupportedEncodingException {
            String cfg = new String(data, "UTF-8");
            if (StringUtils.isNotBlank(cfg)) {
                // 完整的应该还需要处理:多条配置、value中包含=、忽略#号开头
                String[] cfgItem = StringUtils.split(cfg, "=");
                props.put(cfgItem[0], cfgItem[1]);
            }
        }
     
        private byte[] getData(Properties props) throws Exception {
            String path = props.getProperty(PATH);
            Config config = new ZooKeeperConfig();
            return config.getConfig(path);
        }
     
    }
     

    Config.java
    配置操作接口 

    1
    2
    3
    4
    5
    6
    7
    package org.bigmouth.common.zookeeper.config;
     
     
    public interface Config {
     
        byte[] getConfig(String path) throws Exception;
    }



    Startup.java

    程序启动入口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package org.bigmouth.common.zookeeper.config;
     
    import org.springframework.context.support.ClassPathXmlApplicationContext;
     
     
    public class Startup {
     
        public static void main(String[] args) {
            new ClassPathXmlApplicationContext("classpath:/config/applicationContext.xml");
        }
     
    }

    ZooKeeperConfig.java

    配置操作接口ZooKeeper的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package org.bigmouth.common.zookeeper.config;
     
    import org.apache.curator.framework.CuratorFramework;
    import org.apache.zookeeper.data.Stat;
     
     
    public class ZooKeeperConfig implements Config {
     
        @Override
        public byte[] getConfig(String path) throws Exception {
            CuratorFramework client = ZooKeeperFactory.get();
            if (!exists(client, path)) {
                throw new RuntimeException("Path " + path + " does not exists.");
            }
            return client.getData().forPath(path);
        }
         
        private boolean exists(CuratorFramework client, String path) throws Exception {
            Stat stat = client.checkExists().forPath(path);
            return !(stat == null);
        }
     
    }

    ZooKeeperFactory.java

    管理ZooKeeper客户端连接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package org.bigmouth.common.zookeeper.config;
     
    import org.apache.curator.RetryPolicy;
    import org.apache.curator.framework.CuratorFramework;
    import org.apache.curator.framework.CuratorFrameworkFactory;
    import org.apache.curator.retry.ExponentialBackoffRetry;
     
    public class ZooKeeperFactory {
     
        public static final String CONNECT_STRING = "172.16.3.42:2181,172.16.3.65:2181,172.16.3.24:2181";
         
        public static final int MAX_RETRIES = 3;
     
        public static final int BASE_SLEEP_TIMEMS = 3000;
     
        public static final String NAME_SPACE = "cfg";
     
        public static CuratorFramework get() {
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(BASE_SLEEP_TIMEMS, MAX_RETRIES);
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString(CONNECT_STRING)
                    .retryPolicy(retryPolicy)
                    .namespace(NAME_SPACE)
                    .build();
            client.start();
            return client;
        }
    }

    applicationContext.xml

    配置加载器使用我们自己创建的ZooKeeperPropertyPlaceholderConfigurer,因为它重写了processProperties方法。这个方法里会去读取远程配置。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
         
        <bean class="org.bigmouth.common.zookeeper.config.spring.ZooKeeperPropertyPlaceholderConfigurer">
            <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
            <property name="ignoreResourceNotFound" value="true" />
            <property name="locations">
                <list>
                    <value>classpath:application.properties</value>
                </list>
            </property>
        </bean>
         
    </beans>

    application.properties

    项目配置文件,里面除了配置ZooKeeper服务器地址和读取的节点以外,其他所有的配置都应该保存在ZooKeeper中。

    1
    zoo.paths=/properties

    设置ZooKeeper数据

    登录ZooKeeper中为节点 /cfg/properties 添加一条配置项:

    如图所示:我创建了一个节点 /cfg/properties 并设置内容为:jdbc.driver=org.postgresql.Driver

    运行Startup.java

    OK 了,zoo.paths是本地application.properties文件中的,jdbc.driver是远程ZooKeeper服务器中的。

    项目中需要依赖的jar包

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.4</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>3.0.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>3.0.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>3.0.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>3.0.3.RELEASE</version>
    </dependency>
     
    <!-- ZooKeeper -->
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.6</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>2.4.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>2.4.2</version>
    </dependency>
  • 相关阅读:
    模板
    kuangbin带你飞
    BZOJ开荒记
    模板
    洛谷
    模板
    [蓝桥杯][2013年第四届真题]危险系数
    数位DP入门题
    备战2019蓝桥杯
    常用的数学符号
  • 原文地址:https://www.cnblogs.com/wxd0108/p/4871937.html
Copyright © 2020-2023  润新知