热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ZooKeeper学习笔记—配置管理

为什么80%的码农都做不了架构师?最近在工作中,为了完善公司集群服务的架构,提高可用性,降低运维成本,因

为什么80%的码农都做不了架构师?>>>   hot3.png

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

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";@Overrideprotected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)throws BeansException {super.processProperties(beanFactoryToProcess, props);try {fillCustomProperties(props);System.out.println(props);}catch (Exception e) {// Ignoree.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

配置操作接口 

package org.bigmouth.common.zookeeper.config;public interface Config {byte[] getConfig(String path) throws Exception;
}



Startup.java

程序启动入口


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的实现


package org.bigmouth.common.zookeeper.config;import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.data.Stat;public class ZooKeeperConfig implements Config {@Overridepublic 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客户端连接


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方法。这个方法里会去读取远程配置。



classpath:application.properties


application.properties

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

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包


commons-langcommons-lang2.4

org.springframeworkspring-core3.0.3.RELEASE

org.springframeworkspring-context3.0.3.RELEASE

org.springframeworkspring-tx3.0.3.RELEASE

org.springframeworkspring-context-support3.0.3.RELEASE

org.apache.zookeeperzookeeper3.4.6

org.apache.curatorcurator-framework2.4.2

org.apache.curatorcurator-recipes2.4.2

相关资料:

Apache Curator Framework

Apache ZooKeeper



博主,问个zk值被刷了的问题。

假设,我们现在配置的数据,都是从zk中获取的,但是某个值被刷新了,我们有个watch监控到了,但是这个值怎么刷入到内存中,或者说重新注册那个bean?

有没有这方面的解决思路,我有点迷惑

ZKClient 可以轻松监听到配置什么时候变化,但变化后该怎么做?
如果你用了spring,或许这篇文章能帮到你:https://github.com/jamesmorgan/ReloadablePropertiesAnnotation

转载于:https://my.oschina.net/boltwu/blog/464149


推荐阅读
author-avatar
小丸子派大星_127
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有