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> |
ZooKeeper配置管理文件的更多相关文章
- zookeeper配置管理+集群管理实战
引言 之前就了解过kafka,看的似懂非懂,最近项目组中引入了kafka,刚好接着这个机会再次学习下. Kafka在很多公司被用作分布式高性能消息队列,kafka之前我只用过redis的list来做简 ...
- Zookeeper日志文件&事务日志&数据快照
Zookeeper持久化两类数据,Transaction以及Snapshot,logDir存储transaction命令,dataDir存储snap快照,其下子目录名称以version-2命名,子目录 ...
- zookeeper清除日志文件工具
zookeeper运行时间长了以后,日志会成为一个比较大的问题.比如作者压力测试hbase一周以后,zookeeper日志文件达到了10G的规模.由于zookeeper日志文件不能随意删除,因为一个长 ...
- zookeeper 日志输出到指定文件夹
最近在研究Zookeeper Storm Kafka, 顺便在本地搭了一套集群, 遇到了Zookeeper日志问题输出路径的问题, 发现zookeeper设置log4j.properties不能解决日 ...
- Zookeeper 初体验之——伪分布式安装(转)
原文地址: http://blog.csdn.net/salonzhou/article/details/47401069 简介 Apache Zookeeper 是由 Apache Hadoop 的 ...
- spring Boot环境下dubbo+zookeeper的一个基础讲解与示例
一,学习背景 1. 前言 对于我们不管工作还是生活中,需要或者想去学习一些东西的时候,大致都考虑几点: a) 我们为什么需要学习这个东西? b) 这个东西是什么? c) ...
- Zookeeper 快速理解
转自:http://blog.csdn.net/colorant/article/details/8444283 == 是什么 == 目标Scope(解决什么问题) 为分布式系统提供高可靠性的协同工作 ...
- Zookeeper -- 关于Zookeeper
Zookeeper是什么? 分布式协调框架 Zookeeper中文件呈树形结构,树形结构下包含多个节点,称为Znode:zk中节点存储数据不超过1M,指得是Znode中存储数据不超过1M Zookee ...
- ZooKeeper 入门看这篇就够了
什么是 ZooKeeper? ZooKeeper 是一个分布式的,开放源码的分布式应用程序协同服务.ZooKeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原 ...
随机推荐
- AngularJS中实现无限级联动菜单(使用demo)
昨天没来得及贴几个使用demo,今天补上,供有兴趣的同学参考 :) 1. 同步加载子选项demo2. 异步加载子选项demo3. 初始值回填demo4. 倒金字塔依赖demo directive的源代 ...
- 也议 js闭包和ie内存泄露原理
可以, 但小心使用. 闭包也许是 JS 中最有用的特性了. 有一份比较好的介绍闭包原理的文档. 有一点需要牢记, 闭包保留了一个指向它封闭作用域的指针, 所以, 在给 DOM 元素附加闭包时, 很可能 ...
- (十)装饰器模式详解(与IO不解的情缘)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...
- sql 几点记录
1 With子句 1.1 学习目标 掌握with子句用法,并且了解with子句能够提高查询效率的原因. 1.2 With子句要点 with子句的返回结果存到用户的临时表 ...
- C#迭代器
迭代器概述 迭代器是可以返回相同类型的值的有序序列的一段代码. 迭代器可用作方法.运算符或 get 访问器的代码体. 迭代器代码使用 yield return 语句依次返回每个元素.yield bre ...
- Social Emotional Computing -价值观的运算
第三节 价值观的运算 第三节 价值观的运算 由于价值观的客观本质就是事物的价值率,因此价值观的运算在客观本质上就是价值率的运算.由于价值观的运算就是为了揭示不同事物价值观之间的函数关系,因此价值观的 ...
- javascript位置相关知识点整理
1.css指定元素的位置采用的是文档坐标: 2.js查询元素位置的方法返回的是元素在视口中的位置,即视口坐标: 如何获得元素的位置和尺寸 获得元素的位置和尺寸可以通过getBoundingClient ...
- EPEL源
EPEL (Extra Packages for Enterprise Linux)是基于Fedora的一个项目,为“红帽系”的操作系统提供额外的软件包,适用于RHEL.CentOS和Scientif ...
- C++的异常处理之一:throw是个一无是处的东西
看这篇文章学习C++异常处理的基础知识.看完后,还不过瘾,为什么大家在C++代码中都不用Exception?为什么C++11会引入一些变化? 为什么C++ exception handling需要un ...
- Android中的进程与线程
四大组件都是运行在主线程中 1.前台进程:用户正在交互,相当于Activity执行了onResume方法 2.可见进程:用户失去了焦点,相当于Activity执行了onPause方法 3.服务进程:运 ...