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.scanPackageList<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();// registryRegistry registry = RegistryFactory.getSpringRegistry(applicationContext);// 扫描器scanMgr = ScanFactory.getScanMgr(registry);// 第一次扫描并入库 scanMgr.firstScan(scanPackageList);// 获取数据/注入/WatchdisconfCoreMgr = 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 classSet<Class<?>> classdata = reflections.getTypesAnnotatedWith(DisconfFile.class);scanModel.setDisconfFileClassSet(classdata);// 获取DisconfFileItem methodSet<Method> af1 = reflections.getMethodsAnnotatedWith(DisconfFileItem.class);scanModel.setDisconfFileItemMethodSet(af1);// 获取DisconfItem methodaf1 = reflections.getMethodsAnnotatedWith(DisconfItem.class);scanModel.setDisconfItemMethodSet(af1);// 获取DisconfActiveBackupServiceclassdata = reflections.getTypesAnnotatedWith(DisconfActiveBackupService.class);scanModel.setDisconfActiveBackupServiceClassSet(classdata);// 获取DisconfUpdateServiceclassdata = reflections.getTypesAnnotatedWith(DisconfUpdateService.class);scanModel.setDisconfUpdateService(classdata);return scanModel; }
View Code
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修饰的配置更新回调类,该类需实现IDisconfUpdateif (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); }
小结
转载于:https://www.cnblogs.com/xiangnanl/p/9865269.html
disconf原理 “入坑”指南相关推荐
- python这个软件学会能做什么工作-学会Python真的有高收入?盯,请查收这份入坑指南...
学会Python真的有高收入?盯,请查收这份入坑指南 2018-10-10 20:51:00 567点赞 6312收藏 186评论 小编注:想获得更多专属福利吗?金币加成.尊享众测.专属勋章.达人福利 ...
- Rust 入坑指南:鳞次栉比 | CSDN 博文精选
作者 | Jackyzhe 责编 | 屠敏 出品 | CSDN(ID:CSDNnews) 很久没有挖Rust的坑啦,今天来挖一些排列整齐的坑.没错,就是要介绍一些集合类型的数据类型."鳞次栉 ...
- 搜索和CTR预估入坑指南
简介 搜索小白.CTR小白,整理了一份入坑指南,一些比较好的博客和论文.本文适用于有一定的机器学习和深度学习基础,但是不懂搜索和CTR的同学. 注:后续会不定时更新. 基础 主要是一些经典的语言模型( ...
- 信息安全之路入坑指南
作者:腾讯安全平台部研发安全团队 riusksk 疫情下的高考已结束,又快到填志愿的时候了,又有不少知青要加入信息安全这个圈子.为了响应组织号召,撰写此文作为信安行业的入坑指南,希望能对刚入圈的同学有 ...
- Phalcon在Windows上安装 《Phalcon入坑指南系列 一》
Phalcon入坑指南 本系列目录 前言 一.安装 二.Phalcon 开发工具安装 三.环境变量配置 四.Phalcon 开发工具的使用 生成项目框架 生成控制器 / 模型 夸一下phalcon 五 ...
- Rust入坑指南:核心概念
如果说前面的坑我们一直在用小铲子挖的话,那么今天的坑就是用挖掘机挖的. 今天要介绍的是Rust的一个核心概念:Ownership.全文将分为什么是Ownership以及Ownership的传递类型两部 ...
- 一块GPU搞定ChatGPT;ML系统入坑指南;理解GPU底层架构
1. 跑ChatGPT体量模型,从此只需一块GPU 在发展技术,让大模型掌握更多能力的同时,也有人在尝试降低AI所需的算力资源.最近,一种名为FlexGen的技术因为「一块RTX 3090跑ChatG ...
- 发布开源框架到CocoaPods入坑指南
个人原文博客地址: 发布开源框架到CocoaPods入坑指南 在开发过程中一定会用到一些第三方框架, 只要安装了CocoaPods, 然后通过pod install命令, 就可以集成框架到项目中了 可 ...
- python web-python web入坑指南
原标题:python web入坑指南 Invest regularly in your knowledge portfolio. Make learning a habit. 自学python web ...
最新文章
- 没有数学何来计算机:论计算机起源的数学思想
- CSS样式----标记选择器
- IDL关系运算符Eq Ne Le Lt Gt Ge含义说明
- 极致无边界!2021 神策数据 Tech-Day 即将开幕
- Redis集群~StackExchange.redis连接Sentinel服务器并订阅相关事件
- 【Mac】Mac 下 kafka 生产者 控制台 发送长消息被截断
- [Bzoj1009][HNOI2008]GT考试(动态规划)
- 大二暑假假期周进度01
- kafka消费者如何读同一生产者消息_kafka学习笔记
- vs2010启动越来越慢解决方法
- Esxi 6.7u3 安装之重封装网卡驱动与NVME驱动
- webQQ协议——获取信息
- 攻防世界web练习区
- laravel Eloquent whereIn 多个字段
- 淘宝拍立淘以图搜图接口:使用方法和指南
- Sass的概念以及命令
- 外地人一年内直接落户上海
- 【感悟】在工作中勇于走出舒适圈
- 使用MBROSTool 工具制作U盘多启动盘的方法总结
- 下载 | 最新教程《Artifical Neural Networks》