disconf原理 “入坑”指南
之前有了解过disconf,也知道它是基于zookeeper来做的,但是对于其运行原理不太了解,趁着周末,debug下源码,也算是不枉费周末大好时光哈 :) 。关于这篇文章,笔者主要是参考disconf源码和官方文档,若有不正确地方,感谢评论区指正交流~
disconf是一个分布式配置管理平台(Distributed Configuration Management Platform),专注于各种 分布式系统配置管理 的通用组件/通用平台, 提供统一的配置管理服务,是一套完整的基于zookeeper的分布式配置统一解决方案。disconf目前已经被多个公司在使用,包括百度、滴滴出行、银联、网易、拉勾网、苏宁易购、顺丰科技 等知名互联网公司。disconf源码地址 https://github.com/knightliao/disconf ,官方文档 https://disconf.readthedocs.io/zh_CN/latest/ 。
目前disconf包含了 客户端disconf-Client和 管理端disconf-Web两个模块,均由java实现。服务依赖组件包括Nginx、Tomcat、Mysql、ZooKeeper,nginx提供反向代理(disconf-web是前后端分离的),Tomcat是后端web容器,配置存储在mysql上,基于zookeeper的wartch模型,实时推送。注意,disconf优先读取本地文件,disconf只支持应用对配置的读操作,通过在disconf-web上更新配置,然后由zookeeper通知到服务实例,最后服务实例去disconf-web端获取最新配置并更新到本地。
disconf 功能特点:
- 支持配置(配置项/配置文件)分布式管理
- 配置发布统一化
- 配置发布、更新统一化,同一个上线包 无须改动配置 即可在 多个环境中(RD/QA/PRODUCTION) 上线
- 配置更新自动化:用户在平台更新配置,使用该配置的系统会自动发现该情况,并应用新配置。特殊地,如果用户为此配置定义了回调函数类,则此函数类会被自动调用
- 上手简单,基于注解或者xml配置方式
功能特点描述图
disconf 架构图
分析disconf,最好是在本地搭建一个disconf-web环境,方便调试代码,具体步骤可参考官方文档,使用disconf-client,只需要在pom引入依赖即可:
<dependency>
<groupId>com.baidu.disconf</groupId>
<artifactId>disconf-client</artifactId>
<version>2.6.36</version>
</dependency>
对于开发人员来说,最多接触的就是disconf-web配置和disconf-client了,disconf-web配置官方文档已经很详细了,这里就来不及解释了,抓紧上车,去分析disconf-client的实现,disconf-client最重要的内容就是disconf-client初始化流程和配置动态更新机制。disconf的功能是基于Spring的(初始化是在Spring的BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry开始的,配置动态更新也是要更新到Spring IoC中对应的bean),所以使用disconf,项目必须基于Spring。
1 disconf-client 初始化流程
<!-- 使用disconf必须添加以下配置 -->
<bean id="disconfMgrBean" class="com.baidu.disconf.client.DisconfMgrBean"
destroy-method="destroy">
<property name="scanPackage" value="com.luo.demo"/>
</bean>
<bean id="disconfMgrBean2" class="com.baidu.disconf.client.DisconfMgrBeanSecond"
init-method="init" destroy-method="destroy">
</bean>
DisconfMgrBean#postProcessBeanDefinitionRegistry方法主要做的3件事就是扫描(firstScan)、注册DisconfAspectJ 和 bean属性注入。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// scanPackList包括disconf.xml中DisconfMgrBean.scanPackage
List<String> scanPackList = StringUtil.parseStringToStringList(scanPackage, SCAN_SPLIT_TOKEN); // 1. 进行扫描
DisconfMgr.getInstance().setApplicationContext(applicationContext);
DisconfMgr.getInstance().firstScan(scanPackList); // 2. register java bean
registerAspect(registry);
}
1.1 firstScan
protected synchronized void firstScan(List<String> scanPackageList) {
// 导入配置
ConfigMgr.init(); // registry
Registry registry = RegistryFactory.getSpringRegistry(applicationContext); // 扫描器
scanMgr = ScanFactory.getScanMgr(registry); // 第一次扫描并入库
scanMgr.firstScan(scanPackageList); // 获取数据/注入/Watch
disconfCoreMgr = DisconfCoreFactory.getDisconfCoreMgr(registry);
disconfCoreMgr.process();
}
进行包扫描是使用Reflections来完成的,获取路径下(比如xxx/target/classes)某个包下符合条件(比如com.luo.demo)的资源(reflections),然后从reflections获取某些符合条件的资源列表,如下:
/**
* 扫描基本信息
*/
private ScanStaticModel scanBasicInfo(List<String> packNameList) {
ScanStaticModel scanModel = new ScanStaticModel(); // 扫描对象
Reflections reflections = getReflection(packNameList);
scanModel.setReflections(reflections); // 获取DisconfFile class
Set<Class<?>> classdata = reflections.getTypesAnnotatedWith(DisconfFile.class);
scanModel.setDisconfFileClassSet(classdata); // 获取DisconfFileItem method
Set<Method> af1 = reflections.getMethodsAnnotatedWith(DisconfFileItem.class);
scanModel.setDisconfFileItemMethodSet(af1); // 获取DisconfItem method
af1 = reflections.getMethodsAnnotatedWith(DisconfItem.class);
scanModel.setDisconfItemMethodSet(af1); // 获取DisconfActiveBackupService
classdata = reflections.getTypesAnnotatedWith(DisconfActiveBackupService.class);
scanModel.setDisconfActiveBackupServiceClassSet(classdata); // 获取DisconfUpdateService
classdata = reflections.getTypesAnnotatedWith(DisconfUpdateService.class);
scanModel.setDisconfUpdateService(classdata); return scanModel;
}
public static DisconfCoreMgr getDisconfCoreMgr(Registry registry) throws Exception {
FetcherMgr fetcherMgr = FetcherFactory.getFetcherMgr(); // 不开启disconf,则不要watch了
WatchMgr watchMgr = null;
if (DisClientConfig.getInstance().ENABLE_DISCONF) {
// Watch 模块
watchMgr = WatchFactory.getWatchMgr(fetcherMgr);
}
return new DisconfCoreMgrImpl(watchMgr, fetcherMgr, registry);
}
public static WatchMgr getWatchMgr(FetcherMgr fetcherMgr) throws Exception { synchronized(hostsSync) {
// 从disconf-web端获取 Zoo Hosts信息,及zookeeper host和zk prefix信息(默认 /disconf)
hosts = fetcherMgr.getValueFromServer(DisconfWebPathMgr.getZooHostsUrl(DisClientSysConfig
.getInstance()
.CONF_SERVER_ZOO_ACTION));
zooPrefix = fetcherMgr.getValueFromServer(DisconfWebPathMgr.getZooPrefixUrl(DisClientSysConfig
.getInstance
()
.CONF_SERVER_ZOO_ACTION)); /**
* 初始化watchMgr,这里会与zookeeper建立连接,如果/disconf节点不存在会新建
*/
WatchMgr watchMgr = new WatchMgrImpl();
watchMgr.init(hosts, zooPrefix, DisClientConfig.getInstance().DEBUG); return watchMgr;
} return null;
}
1.2 注册DisconfAspectJ
往Spring中注册一个aspect类DisconfAspectJ,该类会对@DisconfFileItem注解修饰的方法做切面,功能就是当获取bean属性值时,如果开启了DisClientConfig.getInstance().ENABLE_DISCONF,则返回disconf仓库中对应的属性值,否则返回bean实际值。注意:目前版本的disconf在更新仓库中属性值后会将bean的属性值也一同更改,所以,目前DisconfAspectJ类作用已不大,不必理会,关于该类的讨论可参考issue DisconfAspectJ 拦截的作用?
1.3 bean属性注入
bean属性注入是从DisconfMgr.secondScan开始的:
protected synchronized void secondScan() {
// 扫描回调函数,也就是注解@DisconfUpdateService修饰的配置更新回调类,该类需实现IDisconfUpdate
if (scanMgr != null) {
scanMgr.secondScan();
} // 注入数据至配置实体中
if (disconfCoreMgr != null) {
disconfCoreMgr.inject2DisconfInstance();
}
}
2 配置动态更新机制
/**
* 更新消息: 某个配置文件 + 回调
*/
@Override
public void updateOneConfAndCallback(String key) throws Exception { // 更新 配置
updateOneConf(key); // 回调
DisconfCoreProcessUtils.callOneConf(disconfStoreProcessor, key);
callUpdatePipeline(key);
}
小结
disconf原理 “入坑”指南的更多相关文章
- Rust入坑指南:核心概念
如果说前面的坑我们一直在用小铲子挖的话,那么今天的坑就是用挖掘机挖的. 今天要介绍的是Rust的一个核心概念:Ownership.全文将分为什么是Ownership以及Ownership的传递类型两部 ...
- electron入坑指南
electron入坑指南 简介 electron 实际集成chrome浏览器和node环境, 运行你写的网页 app 基本目录结构 index.html 名称可以不是index, 这个文件与普通网页的 ...
- C语言入坑指南-被遗忘的初始化
前言 什么是初始化?为什么要初始化?静态变量和局部变量的初始化又有什么区别?实际应用中应该怎么做?本文将一一回答这些问题. 什么是初始化 初始化指的是对数据对象或者变量赋予初始值.例如: int va ...
- Elasticsearch入坑指南之RESTful API
Elasticsearch入坑指南之RESTful API Tags:Elasticsearch ES为开发者提供了非常丰富的基于Http协议的Rest API,通过简单的Rest请求,就可以实现非常 ...
- ElasticSearch入坑指南之概述及安装
---恢复内容开始--- ElasticSearch入坑指南之概述及安装 了解ElasticSearch ElasticSearch(简称ES)基于Lucene的分布式全文检索引擎.使用ES可以实现近 ...
- eclipse中导入外部包却无法查看对应源码或Javadoc的入坑指南
eclipse中导入外部包却无法查看对应源码或Javadoc的 入坑指南 出现这个错误的原因是,你虽然导入了.jar包,但没有配置对应的Javadoc或源码路径,所以在编辑器中无法查看源 码和对应AP ...
- Rust入坑指南:鳞次栉比
很久没有挖Rust的坑啦,今天来挖一些排列整齐的坑.没错,就是要介绍一些集合类型的数据类型."鳞次栉比"这个标题是不是显得很有文化? 在Rust入坑指南:常规套路一文中我们已经介绍 ...
- Rust入坑指南:亡羊补牢
如果你已经开始学习Rust,相信你已经体会过Rust编译器的强大.它可以帮助你避免程序中的大部分错误,但是编译器也不是万能的,如果程序写的不恰当,还是会发生错误,让程序崩溃.所以今天我们就来聊一聊Ru ...
- Rust入坑指南:朝生暮死
今天想和大家一起把我们之前挖的坑再刨深一些.在Java中,一个对象能存活多久全靠JVM来决定,程序员并不需要去关心对象的生命周期,但是在Rust中就大不相同,一个对象从生到死我们都需要掌握的很清楚. ...
随机推荐
- 第二章 运算方法与运算器(浮点数的加减法,IEEE754标准32/64浮点规格化数)
这一章,主要介绍了好多种计算方法.下面,写一点自己对于有些计算(手写计算过程)的见解. 1.原码.反码.补码 原码:相信大家都会写,符号位在前二进制数值在后,凑够位数即可. 反码:原码符号位不变,其他 ...
- jQuery 实现文字不停闪烁效果
使用jQuery实现的小效果:文字不停地闪烁. var flag = true; var text= $('#blink').text(); // blink是需要闪烁的元素id function b ...
- innodb二阶段日志提交机制和组提交解析
前些天在查看关于innodb_flush_log_at_trx_commit的官网解释时产生了一些疑问,关于innodb_flush_log_at_trx_commit参数的详细解释参见官网: htt ...
- SpringBoot集成spring-data-jpa注入Bean失败
当项目结构正常(spring管理的Bean在SrpingBoot启动类平级或下级,支持spring扫描时),实现类上加 @Service注解,在实现类中注入dao层的Bean时,项目无法启动,无法找到 ...
- 利用开机账户登录“轻松访问”创建Windows后门
利用开机账户登录“轻松访问”创建Windows后门 实验原理: 利用登录账户界面的“轻松访问”中的“放大镜”,把它替换为cmd.exe程序,实现在不登录的情况下打开命令提示符,并进行一些操作(打开的c ...
- 登录Windows界面前执行自定义脚本
通常情况下,进入Windows界面之前都有一个登录过程,如何在登录前让系统执行脚本呢?下面介绍一种方法. 1.打开组策略,在Run(运行)中输入GREDIT.MSC,点击确认. 2.依次点击Compu ...
- 【微信小游戏】【提审的坑】!#¥%&……&&……%¥#@@*()()&%%¥
一.开通了虚拟支付后审核变慢 前两个版本是没有开通虚拟支付的,最快一个半小时就过审了.当时还在暗自嘲笑WX,条款很多,审核却那么松,甚至一度怀疑是不是没有审核直接放.然而第三版提审了之后,一个小时.两 ...
- 【C编程基础】C编译链接命令gccc
1.gcc安装 rpm -qa|grep gcc ==>检查gcc是否安装 gcc -v ==>检查gcc版本 yum -y install gcc ==>安装gcc 2.基本语法 ...
- Scrapy 框架 中间件 代理IP 提高效率
中间件 拦截请求跟响应 进行ua(User-Agent ) 伪装 代理 IP 中间件位置: 引擎 和下载器 中间 的中间件 ( 下载中间件) 引擎 跟 spider 中间 的中间件 ( 爬虫中间件)( ...
- TortoiseHg 学习笔记
0.前言 TortoiseHg是分布式的源代码管理工具Mercurial的GUIclient. mercurial 作为3大主流的分布式源代码管理工具.已经被广泛的使用.比如 googleco ...