最近在工作中,为了完善公司集群服务的架构,提高可用性,降低运维成本,因此开始学习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>

ZooKeeper配置管理文件的更多相关文章

  1. zookeeper配置管理+集群管理实战

    引言 之前就了解过kafka,看的似懂非懂,最近项目组中引入了kafka,刚好接着这个机会再次学习下. Kafka在很多公司被用作分布式高性能消息队列,kafka之前我只用过redis的list来做简 ...

  2. Zookeeper日志文件&事务日志&数据快照

    Zookeeper持久化两类数据,Transaction以及Snapshot,logDir存储transaction命令,dataDir存储snap快照,其下子目录名称以version-2命名,子目录 ...

  3. zookeeper清除日志文件工具

    zookeeper运行时间长了以后,日志会成为一个比较大的问题.比如作者压力测试hbase一周以后,zookeeper日志文件达到了10G的规模.由于zookeeper日志文件不能随意删除,因为一个长 ...

  4. zookeeper 日志输出到指定文件夹

    最近在研究Zookeeper Storm Kafka, 顺便在本地搭了一套集群, 遇到了Zookeeper日志问题输出路径的问题, 发现zookeeper设置log4j.properties不能解决日 ...

  5. Zookeeper 初体验之——伪分布式安装(转)

    原文地址: http://blog.csdn.net/salonzhou/article/details/47401069 简介 Apache Zookeeper 是由 Apache Hadoop 的 ...

  6. spring Boot环境下dubbo+zookeeper的一个基础讲解与示例

    一,学习背景 1.   前言 对于我们不管工作还是生活中,需要或者想去学习一些东西的时候,大致都考虑几点: a)      我们为什么需要学习这个东西? b)     这个东西是什么? c)      ...

  7. Zookeeper 快速理解

    转自:http://blog.csdn.net/colorant/article/details/8444283 == 是什么 == 目标Scope(解决什么问题) 为分布式系统提供高可靠性的协同工作 ...

  8. Zookeeper -- 关于Zookeeper

    Zookeeper是什么? 分布式协调框架 Zookeeper中文件呈树形结构,树形结构下包含多个节点,称为Znode:zk中节点存储数据不超过1M,指得是Znode中存储数据不超过1M Zookee ...

  9. ZooKeeper 入门看这篇就够了

    什么是 ZooKeeper? ZooKeeper 是一个分布式的,开放源码的分布式应用程序协同服务.ZooKeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原 ...

随机推荐

  1. 求解最大正方形面积 — leetcode 221. Maximal Square

    本来也想像园友一样,写一篇总结告别 2015,或者说告别即将过去的羊年,但是过去一年发生的事情,实在是出乎平常人的想象,也不具有代表性,于是计划在今年 6 月份写一篇 "半年总结" ...

  2. Windows8.1画热度图 - 坑

    想要的效果 如上是silverlight版本.原理是设定一个调色板,为256的渐变色(存在一个png文件中,宽度为256,高度为1),然后针对要处理的距离矩阵图形,取图片中每个像素的Alpha值作为索 ...

  3. SQL Server output子句用法 output inserted.id 获取刚插入数据的id

    --插入数据,并返回刚刚插入的数据id INSERT INTO [soloreztest] ([name]) output inserted.id VALUES ('solorez') --执行结果: ...

  4. [POJ1284]Primitive Roots(原根性质的应用)

    题目:http://poj.org/problem?id=1284 题意:就是求一个奇素数有多少个原根 分析: 使得方程a^x=1(mod m)成立的最小正整数x是φ(m),则称a是m的一个原根 然后 ...

  5. C# 多线程防止卡死

    软件界面的响应特性是判断一款软件的非常重要的方面.一般来说,不管你软件功能做得有多么奇妙,如果软件有一点点死机的感觉都会让用户感到很讨厌,甚至怀疑你软件里是否藏有更大的问题. 要提高界面的响应特性,最 ...

  6. 作业4-两人编程<词频统计>

     协作:苗中峰,刘鑫成       我主要攻克排序,成哥写了文件流的使用.整合工作由我完成,成哥帮我查阅资料,避免和解决语法错误.              这次任务较作业三的变化是:       * ...

  7. ASP.NET配置Ueditor编辑器上传图片路径

    1.配置ueditor/editor_config.js文件,将 //图片上传配置区 ,imageUrl:URL+"net/imageUp.ashx" //图片上传提交地址 ,im ...

  8. java设计优化--代理模式

    代理模式使用代理对象完成用户的请求,屏蔽用户对真实对象的访问. 代理模式的用途很多,比如因为安全原因,需要屏蔽客户端直接访问真实对象:或者在远程调用中,需要使用代理对象处理远程方法中的技术细节:或者为 ...

  9. jquery里的on方法使用

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <script src ...

  10. 在Windows .NET平台下使用Memcached

    网上关于Memcached的文章很多,但据我观察,大多是互相转载或者抄袭的,千篇一律.有些则是直接整理的一些超链接然后贴出来.那些超链接笔者大概都进去看了,其实关于Memcached的中文的技术文章, ...