博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ZooKeeper配置管理文件
阅读量:5940 次
发布时间:2019-06-19

本文共 6983 字,大约阅读时间需要 23 分钟。

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

转载地址:http://bhmtx.baihongyu.com/

你可能感兴趣的文章
Apache Spark 2.0预览: 机器学习模型持久化
查看>>
技术指导实践指南
查看>>
GitHub上的编程语言:JavaScript领衔Java次之
查看>>
微软发布了Spartan项目的细节,并证实了某些流言
查看>>
全面了解大数据“三驾马车”的开源实现
查看>>
.NET Core 2.1预览分层编译特性
查看>>
公有云还能信任吗?Azure遭雷击中断超过一天
查看>>
量子计算竞速时代,如何拨动时间的指针
查看>>
统计php脚本执行时间的php扩展
查看>>
华中科大提出EAT-NAS方法:提升大规模神经模型搜索速度
查看>>
Spring框架5.1将提供对Java 11的支持
查看>>
切勿版本化Web API
查看>>
SpringOne 2017第二日:Juergen Hoeller的演讲
查看>>
Hyperledger Composer评测
查看>>
差分隐私简介
查看>>
Java将弃用finalize()方法?
查看>>
Apache Pulsar中的地域复制,第1篇:概念和功能
查看>>
干净架构在 Web 服务开发中的实践
查看>>
云原生的浪潮下,为什么运维人员适合学习Go语言?
查看>>
Puppet 4 性能提升超2倍,升级前应该你知悉的变化
查看>>