2020-03-24 15:46:29
应用项目中都会有一些参数,一般的做法通常可以选择将其存储在本地配置文件或者内存变量中;对于集群机器规模不大、配置变更不是特别频繁的情况下,这两种方式都能很好的解决;但是一旦集群机器规模变大,且配置信息越来越频繁,依靠这两种方式就越来越困难;我们希望能够快速的做到全局参数的变更,因此需要一种参数的集中式管理,下面利用Zookeeper的一些特性来实现简单的参数管理。
jdk:1.7.0_80
zookeeper:3.4.3
curator:2.6.0
spring:3.1.2
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.3</version>
<exclusions>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.6.0</version>
</dependency>
1、可以同时配置监听多个节点如/app1,/app2;
2、希望只需要配置如/app1,就能够监听其子节点如/app1/modual1以及子节点的子节点如/app1/modual1/xxx/…;
3、服务器启动能获取当前指定父节点下的所有子节点数据;
4、在添加节点或者在更新节点数据的时候能够动态通知,这样代码中就能够实时获取最新的数据;
5、spring配置中可以从Zookeeper中读取参数进行初始化。
提供ZKWatcher类主要用来和Zookeeper建立连接,监听节点,初始化节点数据,更新节点数据,存储节点数据等
提供一个字符串数组给用户用来添加需要监听的节点:
private String[] keyPatterns;
使用递归的方式用来获取指定监听节点的子节点:
private List<String> listChildren(String path) throws Exception {
List<String> pathList = new ArrayList<String>();
pathList.add(path);
List<String> list = client.getChildren().forPath(path);
if (list != null && list.size() > 0) {
for (String cPath : list) {
String temp = "";
if ("/".equals(path)) {
temp = path + cPath;
} else {
temp = path + "/" + cPath;
}
pathList.addAll(listChildren(temp));
}
}
return pathList;
}
上面已经递归获取了所有的节点,所有可以遍历获取所有节点数据,并且存储在Map中:
private Map<String, String> keyValueMap = new ConcurrentHashMap<String, String>();
if (pathList != null && pathList.size() > 0) {
for (String path : pathList) {
keyValueMap.put(path, readPath(path));
watcherPath(path);
}
}
private String readPath(String path) throws Exception {
byte[] buffer = client.getData().forPath(path);
String value = new String(buffer);
logger.info("readPath:path = " + path + ",value = " + value);
return value;
}
使用PathChildrenCache用来监听子节点的CHILD_ADDED,CHILD_UPDATED,CHILD_REMOVED事件:
private void watcherPath(String path) {
PathChildrenCache cache = null;
try {
cache = new PathChildrenCache(client, path, true);
cache.start(StartMode.POST_INITIALIZED_EVENT);
cache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
switch (event.getType()) {
case CHILD_ADDED:
logger.info("CHILD_ADDED," + event.getData().getPath());
watcherPath(event.getData().getPath());
keyValueMap.put(event.getData().getPath(), new String(event.getData().getData()));
break;
case CHILD_UPDATED:
logger.info("CHILD_UPDATED," + event.getData().getPath());
keyValueMap.put(event.getData().getPath(), new String(event.getData().getData()));
break;
case CHILD_REMOVED:
logger.info("CHILD_REMOVED," + event.getData().getPath());
break;
default:
break;
}
}
});
} catch (Exception e) {
if (cache != null) {
try {
cache.close();
} catch (IOException e1) {
}
}
logger.error("watch path error", e);
}
}
实现自定义的PropertyPlaceholderConfigurer类ZKPropPlaceholderConfigurer:
public class ZKPropPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
private ZKWatcher zkwatcher;
@Override
protected Properties mergeProperties() throws IOException {
return loadPropFromZK(super.mergeProperties());
}
/**
* 从zk中加载配置的常量
*
* @param result
* @return
*/
private Properties loadPropFromZK(Properties result) {
zkwatcher.watcherKeys();
zkwatcher.fillProperties(result);
return result;
}
......
}
通过以上的处理,可以使用如下简单的配置来达到目标:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean class="zh.maven.DynamicConf.ZKWatcher">
<property name="keyPatterns" value="/a2,/a3/m1" />
</bean>
<bean class="zh.maven.DynamicConf.ZKPropPlaceholderConfigurer">
<property name="zkwatcher" ref="zkwatcher"></property>
</bean>
<bean class="zh.maven.DynamicConf.Person">
<property name="name">
<value>${/a2/m1}</value>
</property>
<property name="address">
<value>${/a3/m1/v2}</value>
</property>
<property name="company">
<value>${/a3/m1/v2/t2}</value>
</property>
</bean>
</beans>
详细代码svn地址:http://code.taobao.org/svn/temp-pj/DynamicConf
zkServer.cmd
public class Create_Node {
static String path = "/a3/m1/v2/t2";
static CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("127.0.0.1:2181").sessionTimeoutMs(5000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
public static void main(String[] args) throws Exception {
client.start();
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.forPath(path, "init".getBytes());
}
}
创建需要的节点方便ZKWatcher来监听,这里根据以上的配置,分别初始化/a3/m1/v2/t2和/a2/m1/v1/t1
public class Main {
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "spring-config.xml" });
Person person = (Person) context.getBean("person");
System.out.println(person.toString());
ZKWatcher zkwatcher = (ZKWatcher) context.getBean("zkwatcher");
while (true) {
Person p = new Person(zkwatcher.getKeyValue("/a2/m1"), zkwatcher.getKeyValue("/a3/m1/v2"),
zkwatcher.getKeyValue("/a3/m1/v2/t2"));
System.out.println(p.toString());
Thread.sleep(1000);
}
}
}
public class Set_Data {
static String path = "/a3/m1/v2/t2";
static CuratorFramework client = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181")
.sessionTimeoutMs(5000).retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
public static void main(String[] args) throws Exception {
client.start();
Stat stat = new Stat();
System.out.println(stat.getVersion());
System.out.println("Success set node for :" + path + ",new version:"
+ client.setData().forPath(path, "codingo_v2".getBytes()).getVersion());
}
}
部分日志如下:
2017-08-05 18:04:57 - watcher path : [/a2, /a2/m1, /a2/m1/v1, /a2/m1/v1/t2, /a3/m1, /a3/m1/v2, /a3/m1/v2/t2]
2017-08-05 18:04:57 - readPath:path = /a2,value =
2017-08-05 18:04:57 - readPath:path = /a2/m1,value = zhaohui
2017-08-05 18:04:57 - readPath:path = /a2/m1/v1,value =
2017-08-05 18:04:57 - readPath:path = /a2/m1/v1/t2,value = init
2017-08-05 18:04:57 - readPath:path = /a3/m1,value =
2017-08-05 18:04:57 - readPath:path = /a3/m1/v2,value = nanjing
2017-08-05 18:04:57 - readPath:path = /a3/m1/v2/t2,value = codingo_v10
2017-08-05 18:04:57 - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@182f4aea: defining beans [zkwatcher,propertyConfigurer,person]; root of factory hierarchy
name = zhaohui,address = nanjing,company = codingo_v10
name = zhaohui,address = nanjing,company = codingo_v10
2017-08-05 18:04:57 - CHILD_ADDED,/a2/m1
2017-08-05 18:04:57 - CHILD_ADDED,/a3/m1/v2
2017-08-05 18:04:57 - CHILD_ADDED,/a2/m1/v1
2017-08-05 18:04:57 - CHILD_ADDED,/a2/m1/v1/t2
2017-08-05 18:04:57 - CHILD_ADDED,/a3/m1/v2/t2
name = zhaohui,address = nanjing,company = codingo_v10
name = zhaohui,address = nanjing,company = codingo_v10
name = zhaohui,address = nanjing,company = codingo_v10
2017-08-05 18:05:04 - CHILD_UPDATED,/a3/m1/v2/t2
name = zhaohui,address = nanjing,company = codingo_v11
name = zhaohui,address = nanjing,company = codingo_v11
通过Zookeeper实现了一个简单的参数化平台,当然想在生产中使用还有很多需要优化的地方,本文在于提供一个思路;当然除了Zookeeper还可以使用MQ,分布式缓存等来实现参数化平台。
Zookeeper安装部署(单点/集群)
02-14
管理swarm(3) – swarm实践 – 环境准备
07-18
IdeaPad Z470/Y470 如何使用散热管理
06-29
Linux screen多重视窗管理程序命令详解
07-05
MariaDB初学者管理命令
07-13
T100 G9选配显卡参数及驱动编号
05-23
Vista设置有线和无线网络参数的方法
06-16
Win7如何清除资源管理器中地址栏中的历史记录
07-14
Windows 7下用磁盘管理为硬盘分区
07-13
eAccelerator 参数详解
03-27
使用 Vagrant 管理虚拟机
07-23
如何通过联想电源管理软件调整电源模式
07-01
扬天系列预装Think机型Power Manger电源管理及快捷键驱动的卸载和安装说明
06-29
联想摄像头随机软件能否保存视频捕捉属性以及视频捕捉参数?
03-07
设备管理器未知设备硬件ID:ACPI/CTL0002 的解决方案
07-10
ActiveMQ基于Zookeeper的主从(levelDB Master/Slave)搭建
07-11
Docker创建的集群下使用ansible部署Zookeeper
04-26
Linux 的系统服务及其配置
07-07
Y650如何安装联想的一键影音(Onekey Theater)
07-05
linux常用命令介绍
06-30
3dmax场景助手(3d建模类场景设计管理工) 4.1.10 最新版
0.17MB
下载Apowersoft手机管理大师下载
68.3M
下载bosskey(窗口管理工具)v0.4.6.2 免费版
268KB
下载virtual drive manager(虚拟驱动器管理工具) V1.32 绿色版
0.21MB
下载客户达开店管家(淘宝店铺管理软件) v4.09 破解版
40.2MB
下载旺财流水账(财务管理软件) 9.2 免费版
4.85MB
下载百卓优采云进销存(进销存管理工具) v5.6.69.2 免费版
28.8M
下载HeidiSQL下载
10.1M
下载endnote x7下载
114MB
下载mt4下载
3.2M
下载realtek hd下载
77.7M
下载印象笔记下载
122.6M
下载叮当管家下载
32.61 MB
下载家庭记账软件下载
2.0M
下载网易邮箱大师下载
28.3M
下载