Zookeeper笔记之基于zk的分布式配置中心
一、场景 & 需求
集群上有很多个节点运行同一个任务,这个任务会有一些可能经常改变的配置参数,要求是当配置参数改变之后能够很快地同步到每个节点上,如果将这些配置参数放在本地文件中则每次都要修改本地文件费时费力还可能会有遗漏,所以这个时候一个比较自然的想法就是将配置单独提取出来作为一个服务,比如自己开发一个http服务器提供一个接口来获取服务,这有两个问题,其一是配置下发这其实是一个推模型,当配置发生改变时需要服务器去主动推给客户端而不是客户端不断地去轮询,其二是配置中心不能是单点故障,对配置中心的可用性有一定要求,这时候如果有zookeeper集群的话直接拿来作为配置中心使用不失为一种简单的方案。
二、分析
一个配置中心的核心是什么:
1. 低延迟:配置改变后能够尽快的将最新配置同步给每一个节点。
2. 高可用:配置中心需要能够稳定不间断的提供服务。
第一点可以通过zookeeper的watcher机制实现,约定一个节点用来存放配置信息,每个客户端都监听这个节点的NodeDataChanged事件,当配置发生改变时将最新的配置更新到这个节点上(谁更新无所谓,任意一个节点都可以更新,或者做一个另外的配置管理后台用来更新都没有问题),这个节点触发NodeDataChanged事件,通知所有监听此节点NodeDataChanged事件的客户端获取此节点的最新值,因为watcher是一次性的,所以在获取最新值的时候需要重新设置监听事件,因为getData是原子性操作,所以能够保证获取到的一定是最新的值。这里需要注意的是存放在节点上的配置文件不宜过大,如果配置文件部分很大而每次变更的只是一部分的话或许可以考虑对其进行拆分,存放在多个节点上。
第二点的高可用性就是交由zookeeper集群来保证,在应用层面不需要做额外的工作。
下面是分布式配置管理中心简单的示意图:

程序运行过程中不断的重复123步骤。
三、代码实现
ConfigManager.java:
package cc11001100.zookeeper.configManager; import cc11001100.zookeeper.utils.ZooKeeperUtil;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooKeeper; import java.io.IOException; /**
* 使用zookeeper做分布式配置管理的例子
*
* @author CC11001100
*/
public class ConfigManager { private String configNode;
private ZooKeeper zooKeeper; public ConfigManager(String configNode) throws IOException {
this.configNode = configNode;
zooKeeper = ZooKeeperUtil.getZooKeeper();
registerConfigChangeListener();
} private void registerConfigChangeListener() {
try {
byte[] newConfig = zooKeeper.getData(configNode, event -> registerConfigChangeListener(), null);
if (newConfig != null) {
handleNewConfig(new String(newConfig, "UTF-8"));
}
} catch (IOException | InterruptedException | KeeperException e) {
e.printStackTrace();
}
} protected void handleNewConfig(String newConfig) {
System.out.println(Thread.currentThread().getName() + " config changed: " + newConfig);
} public void updateConfig(String newConfig) {
try {
zooKeeper.setData(configNode, newConfig.getBytes(), -1);
} catch (InterruptedException | KeeperException e) {
e.printStackTrace();
}
} }
ConfigManagerTest.java:
package cc11001100.zookeeper.configManager; import cc11001100.zookeeper.utils.ZooKeeperUtil;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper; import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit; /**
* 测试更新
*
* @author CC11001100
*/
public class ConfigManagerTest { private static void sleep(int mils) {
try {
TimeUnit.MILLISECONDS.sleep(mils);
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void main(String[] args) throws IOException, KeeperException, InterruptedException { final String CONFIG_NODE = "/config-node";
ZooKeeper zooKeeper = ZooKeeperUtil.getZooKeeper();
if (zooKeeper.exists(CONFIG_NODE, false) == null) {
zooKeeper.create(CONFIG_NODE, "default-config".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
} // 模拟有10个客户端,每个都有一定几率更新配置
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
ConfigManager configManager = new ConfigManager(CONFIG_NODE);
Random random = new Random();
sleep(random.nextInt(3000));
while (true) {
if (Math.random() < 0.2) {
// 节点可以自己更新配置
String newConfig = Thread.currentThread().getName() + " update, new config " + random.nextLong();
configManager.updateConfig(newConfig);
}
sleep(3000);
}
} catch (IOException e) {
e.printStackTrace();
}
}, "client-" + i).start();
} // 也可以有专门的配置中心来管理更新配置
Random random = new Random();
while (true) {
if (Math.random() < 0.2) {
String newConfig = "config master update, new config " + random.nextLong();
zooKeeper.setData(CONFIG_NODE, newConfig.getBytes(), -1);
}
sleep(1000);
} } }
控制台输出:
...
client-4 config changed: client-5 update, new config -845834592719987179
client-5 config changed: client-5 update, new config -845834592719987179
client-3 config changed: client-5 update, new config -845834592719987179
client-6 config changed: client-5 update, new config -845834592719987179
client-1 config changed: client-5 update, new config -845834592719987179
client-7 config changed: client-5 update, new config -845834592719987179
client-2 config changed: client-5 update, new config -845834592719987179
client-8 config changed: client-5 update, new config -845834592719987179
client-9 config changed: client-5 update, new config -845834592719987179
client-0 config changed: client-5 update, new config -845834592719987179
client-1-EventThread config changed: config master update, new config -1193927892495196391
client-2-EventThread config changed: config master update, new config -1193927892495196391
client-6-EventThread config changed: config master update, new config -1193927892495196391
client-9-EventThread config changed: config master update, new config -1193927892495196391
client-8-EventThread config changed: config master update, new config -1193927892495196391
client-3-EventThread config changed: config master update, new config -1193927892495196391
client-4-EventThread config changed: config master update, new config -1193927892495196391
client-7-EventThread config changed: config master update, new config -1193927892495196391
client-5-EventThread config changed: config master update, new config -1193927892495196391
client-0-EventThread config changed: config master update, new config -1193927892495196391
client-1-EventThread config changed: client-9 update, new config -3172102246096982581
client-6-EventThread config changed: client-9 update, new config -3172102246096982581
client-0-EventThread config changed: client-9 update, new config -3172102246096982581
client-2-EventThread config changed: client-9 update, new config -3172102246096982581
client-4-EventThread config changed: client-9 update, new config -3172102246096982581
client-7-EventThread config changed: client-9 update, new config -3172102246096982581
client-8-EventThread config changed: client-9 update, new config -3172102246096982581
client-9-EventThread config changed: client-9 update, new config -3172102246096982581
client-5-EventThread config changed: client-9 update, new config -3172102246096982581
client-3-EventThread config changed: client-9 update, new config -3172102246096982581
client-8-EventThread config changed: config master update, new config -8802002496608532059
client-2-EventThread config changed: config master update, new config -8802002496608532059
client-4-EventThread config changed: config master update, new config -8802002496608532059
client-1-EventThread config changed: config master update, new config -8802002496608532059
client-6-EventThread config changed: config master update, new config -8802002496608532059
client-7-EventThread config changed: config master update, new config -8802002496608532059
client-0-EventThread config changed: config master update, new config -8802002496608532059
client-5-EventThread config changed: config master update, new config -8802002496608532059
client-9-EventThread config changed: config master update, new config -8802002496608532059
client-3-EventThread config changed: config master update, new config -8802002496608532059
client-4-EventThread config changed: client-2 update, new config -4848584377488801943
client-1-EventThread config changed: client-2 update, new config -4848584377488801943
client-6-EventThread config changed: client-2 update, new config -4848584377488801943
client-2-EventThread config changed: client-2 update, new config -4848584377488801943
client-8-EventThread config changed: client-2 update, new config -4848584377488801943
client-7-EventThread config changed: client-2 update, new config -4848584377488801943
client-5-EventThread config changed: client-2 update, new config -4848584377488801943
client-9-EventThread config changed: client-2 update, new config -4848584377488801943
client-3-EventThread config changed: client-2 update, new config -4848584377488801943
client-0-EventThread config changed: client-2 update, new config -4848584377488801943
client-6-EventThread config changed: client-9 update, new config 6591542797374556406
client-4-EventThread config changed: client-9 update, new config 6591542797374556406
client-3-EventThread config changed: client-9 update, new config 6591542797374556406
client-9-EventThread config changed: client-9 update, new config 6591542797374556406
client-1-EventThread config changed: client-9 update, new config 6591542797374556406
client-2-EventThread config changed: client-9 update, new config 6591542797374556406
client-8-EventThread config changed: client-9 update, new config 6591542797374556406
client-7-EventThread config changed: client-9 update, new config 6591542797374556406
client-0-EventThread config changed: client-9 update, new config 6591542797374556406
client-5-EventThread config changed: client-9 update, new config 6591542797374556406
client-6-EventThread config changed: client-8 update, new config -6225415529835558983
client-4-EventThread config changed: client-8 update, new config -6225415529835558983
client-8-EventThread config changed: client-8 update, new config -6225415529835558983
client-2-EventThread config changed: client-8 update, new config -6225415529835558983
client-1-EventThread config changed: client-8 update, new config -6225415529835558983
client-5-EventThread config changed: client-8 update, new config -6225415529835558983
client-0-EventThread config changed: client-8 update, new config -6225415529835558983
client-7-EventThread config changed: client-8 update, new config -6225415529835558983
client-9-EventThread config changed: client-8 update, new config -6225415529835558983
client-3-EventThread config changed: client-8 update, new config -6225415529835558983
client-1-EventThread config changed: client-4 update, new config -703954571020619435
client-4-EventThread config changed: client-4 update, new config -703954571020619435
client-8-EventThread config changed: client-4 update, new config -703954571020619435
client-6-EventThread config changed: client-4 update, new config -703954571020619435
client-2-EventThread config changed: client-4 update, new config -703954571020619435
client-7-EventThread config changed: client-4 update, new config -703954571020619435
client-0-EventThread config changed: client-4 update, new config -703954571020619435
client-5-EventThread config changed: client-4 update, new config -703954571020619435
client-3-EventThread config changed: client-4 update, new config -703954571020619435
client-9-EventThread config changed: client-4 update, new config -703954571020619435
...
四、总结
使用zk作为配置分发的优点是低延迟、高可靠性,当然也有缺点,因为watcher是跟会话绑定的,而要维护每个会话需要一个tcp一直连接到服务器,这对集群来说也是一种负载,不过考虑到2c4g单台机器支持几百连接并发很轻松,再加上整个zookeeper集群中会有多台机器平均一下,这点负载基本忽略了。
相关资料:
1. 一篇好TM长的关于配置中心的文章 - 阿里中间件团队博客(废话有点多,但很值得一看)
.
Zookeeper笔记之基于zk的分布式配置中心的更多相关文章
- zookeeper笔记之基于zk实现分布式锁
一.分布式锁概述 Java中基于AQS框架提供了一系列的锁,但是当需要在集群中的多台机器上互斥执行一段代码或使用资源时Java提供的这种单机锁就没了用武之地,此时需要使用分布式锁协调它们.分布式锁有很 ...
- 基于ZK构建统一配置中心的方案和实践
背景: 近期使用Zk实现了一个简单的配置管理的小东西,在此开源出来,有兴趣的希望提出您的宝贵意见.如果恰巧您也使用或者接触过类似的东西, 也希望您可以分享下您觉得现在这个项目可以优化和改进的地方. 项 ...
- 基于zookeeper实现分布式配置中心(一)
最近在学习zookeeper,发现zk真的是一个优秀的中间件.在分布式环境下,可以高效解决数据管理问题.在学习的过程中,要深入zk的工作原理,并根据其特性做一些简单的分布式环境下数据管理工具.本文首先 ...
- 基于zookeeper实现分布式配置中心(二)
上一篇(基于zookeeper实现分布式配置中心(一))讲述了zookeeper相关概念和工作原理.接下来根据zookeeper的特性,简单实现一个分布式配置中心. 配置中心的优势 1.各环境配置集中 ...
- spring cloud 入门系列七:基于Git存储的分布式配置中心
我们前面接触到的spring cloud组件都是基于Netflix的组件进行实现的,这次我们来看下spring cloud 团队自己创建的一个全新项目:Spring Cloud Config.它用来为 ...
- 基于winserver的Apollo配置中心分布式&集群部署实践(正确部署姿势)
基于winserver的Apollo配置中心分布式&集群部署实践(正确部署姿势) 前言 前几天对Apollo配置中心的demo进行一个部署试用,现公司已决定使用,这两天进行分布式部署的时候 ...
- spring cloud 入门系列七:基于Git存储的分布式配置中心--Spring Cloud Config
我们前面接触到的spring cloud组件都是基于Netflix的组件进行实现的,这次我们来看下spring cloud 团队自己创建的一个全新项目:Spring Cloud Config.它用来为 ...
- SpringCloud学习笔记(九):SpringCloud Config 分布式配置中心
概述 分布式系统面临的-配置问题 微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务.由于每个服务都需要必要的配置信息才能运行,所以一套集中式的.动 ...
- SpringCloud搭建分布式配置中心(基于git)
1.简介 Spring Cloud Config.它用来为分布式系统中的基础设施和微服务提供集中化的外部配置支持,分为服务端和客户端两个部分. 其中服务端也称为分布式配置中心,他是独立的微服务应用,用 ...
随机推荐
- The role of the inter-controller consensus in the placement of distributed SDN controllers
2017 Computer Communications 问题:in-band网络的多控制器放置问题,考虑到多个控制器之间的同步(Ctr-Ctr)可能影响到控制器与交换机(Ctr-Sw)的时延: 关于 ...
- Beta版本冲刺(五)
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:恺琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...
- 软件工程学习之小学四则混合运算出题软件 Version 1.00 设计思路及感想
对于小学四则混合运算出题软件的设计,通过分析设计要求,我觉得为了这个软件在今后便于功能上的扩充,可以利用上学期所学习的<编译原理>一课中的LL1语法分析及制导翻译的算法来实现.这样做的好处 ...
- Alpha冲刺第10天
Alpha第10天 1.团队成员 郑西坤 031602542 (队长) 陈俊杰 031602504 陈顺兴 031602505 张胜男 031602540 廖钰萍 031602323 雷光游 0316 ...
- HDU 2029 算菜价
http://acm.hdu.edu.cn/showproblem.php?pid=2090 Problem Description 妈妈每天都要出去买菜,但是回来后,兜里的钱也懒得数一数,到底花了多 ...
- Linux命令(三) 移动文件 mv
用户可以使用 mv 命令来移动文件或目录至另一个文件或目录, 还可以将目录或文件重命名. 如果将一个文件移动到一个已经存在的目标文件中,目标文件的内容将会被覆盖.mv 命令接收两个参数时,第一个参数表 ...
- linux 取消控制台报警音
可以通过setterm -blength 0 设置报警音报警时间,0表示没有报警音 也可以通过setterm -bfreq 10 设置报警音的频率(Hz) 如果通过命令行直接设置,当下会生效,但是重启 ...
- 洛谷 P1361 小M的作物 解题报告
P1361 小M的作物 题目描述 小M在MC里开辟了两块巨大的耕地\(A\)和\(B\)(你可以认为容量是无穷),现在,小\(P\)有\(n\)中作物的种子,每种作物的种子有1个(就是可以种一棵作物) ...
- 使用highlight.js高亮静态页面的语言代码
显示静态的代码其实html的pre标签基本可以满足需求了,至少不会将换行的文本显示成一堆字符串. 不过能使静态的文本能高亮显示,倒更炫酷一点.其实很简单的,引入highlight.js包,可以使用cd ...
- js中全局变量修改后的值不生效【jsp页面中各个js中内容的加载顺序】
一个老项目中,一个jsp文件中有很多个js文件, 现在要在页面上的一个地方判断一个状态,因为一直找不到原来是在哪里修改的那个状态,所以决定不找了,而是在比较靠前引入的一个js中定义一个全局变量,然后在 ...