为了更好的解决分布式环境下多台服务实例的配置统一管理问题,本文提出了一套完整的分布式配置管理解决方案(简称为disconf[4],下同)。首先,实现了同构系统的配置发布统一化,提供了配置服务server,该服务能够对配置进行持久化管理并对外提供restful接口,在此基础上,基于zookeeper实现对配置更改的实时推送,而且,提供了稳定有效的容灾方案,以及用户体验良好的编程模型和WEB用户管理界面。其次,实现了异构系统的配置包管理,提出基于zookeeper的全局分布式一致性锁来实现主备统一部署、系统异常时的主备自主切换。经过在百度内部以及外部等多个产品线的实践结果代表,本解决方案是有效且稳定的。mysql
在一个分布式环境中,同类型的服务每每会部署不少实例。这些实例使用了一些配置,为了更好地维护这些配置就产生了配置管理服务。经过这个服务能够轻松地管理成千上百个服务实例的配置问题。git
王阿晶提出了基于zooKeeper的配置信息存储方案的设计与实现[1], 它将全部配置存储在zookeeper上,这会致使配置的管理不那么方便,并且他们没有相关的源码实现。淘宝的diamond[2]是淘宝内部使用的一个管理持久配置的系统,它具备完整的开源源码实现,它的特色是简单、可靠、易用,淘宝内部绝大多数系统的配置都采用diamond来进行统一管理。他将全部配置文件里的配置打散化进行存储,只支持KV结构,而且配置更新的推送是非实时的。百度内部的BJF配置中心服务[3]采用了相似淘宝diamond的实现,也是配置打散化、只支持KV和非实时推送。程序员
同构系统是市场的主流,特别地,在业界大量使用部署虚拟化(如JPAAS系统,SAE,BAE)的状况下,同一个系统使用同一个部署包的情景会愈来愈多。可是,异构系统也有必定的存在乎义,譬如,对于“拉模式”的多个下游实例,同一时间点只能只有一个下游实例在运行。在这种情景下,就存在多台实例机器有“主备机”模式的问题。目前国内并无很明显的解决方案来统一解决此问题。github
disconf是一套完整的基于zookeeper的分布式配置统一解决方案。web
它的功能特色是redis
它的设计理念是:spring
disconf服务集群模式:sql
disconf的模块架构图:数据库
每一个模块的简单介绍以下:编程
运行流程详细介绍:
与2.0版本的主要区别是支持了:主备分配功能/主备切换事件。
disconf-web提供了先后端分离的web架构,具体可见:https://github.com/knightliao/disconf/tree/master/disconf-web
本部分会重点介绍disconf-client的实现方式。
本实现会涉及到 配置仓库容器模块、扫描模块、下载模块、watch模块,
使用AOP拦截的一个好处是能够比较轻松的实现配置控制,好比并发环境下的配置统一辈子效。关于这方面的讨论能够见这里。
特别地,本方式提供的编程模式很是简单,例如使用如下配置类的程序在使用它时,能够直接@Autowired进来进行调用,使用它时就和日常使用普通的JavaBean同样,但其实它已经分布式化了。配置更新时,配置类亦会自动更新。
@Service @DisconfFile(filename = "redis.properties") public class JedisConfig { // 表明链接地址 private String host; // 表明链接port private int port; /** * 地址, 分布式文件配置 * * @return */ @DisconfFileItem(name = "redis.host", associateField = "host") public String getHost() { return host; } public void setHost(String host) { this.host = host; } /** * 端口, 分布式文件配置 * * @return */ @DisconfFileItem(name = "redis.port", associateField = "port") public int getPort() { return port; } public void setPort(int port) { this.port = port; } }
本实现提供了无任何代码侵入方式的分布式配置。
ReloadablePropertiesFactoryBean继承了Spring Properties文件的PropertiesFactoryBean类,管理全部当配置更新时要进行reload的配置文件。对于被管理的每个配置文件,都会经过 配置仓库容器模块、扫描模块、下载模块、watch模块 进行配置获取至配置仓库里。
ReloadingPropertyPlaceholderConfigurer继承了Spring Bean配置值控制类PropertyPlaceholderConfigurer。在第一次扫描spring bean里,disconf会记录配置文件的配置与哪些bean有关联。
ReloadConfigurationMonitor是一个定时任务,定时check本地配置文件是否有更新。
当配置中心的配置被更新时,配置文件会被下载至实例本地,ReloadConfigurationMonitor即会监控到此行为,而且通知 ReloadingPropertyPlaceholderConfigurer 对相关的bean类进行值更新。
特别的,此种方式没法解决并发状况下配置统一辈子效的问题。
在实现中,为每一个配置提供主备选择的概念。用户实例在获取配置前须要先进行全局惟一性竞争才能获得配置值。在这里,咱们采用基于zookeeper的全局惟一性锁来实现。
淘宝Diamond[2] | Disconf | 比较 | |
---|---|---|---|
数据持久性 | 存储在mysql上 | 存储在mysql上 | 都持久化到数据库里,都易于管理 |
推拉模型 | 拉模型,每隔15s拉一次全量数据 | 基于Zookeeper的推模型,实时推送 | disconf基于分布式的Zookeeper来实时推送,在稳定性、实效性、易用性上均优于diamond |
配置读写 | 支持实例对配置读写。支持某台实例写配置数据,并广播到其它实例上 | 只支持实例对配置读。经过在disconf-web上更新配置到达到广播写到全部应用实例 | 从目前的应用场景来看,实例对配置的写需求不是那么明显。disconf支持的中心化广播方案可能会与人性思考更加类似。 |
容灾 | 多级容灾模式,配置数据会dump在本地,避免中心服务挂机时没法使用 | 多级容灾模式,优先读取本地配置文件。 | 双方均支持在中心服务挂机时配置实例仍然可使用 |
配置数据模型 | 只支持KV结构的数据,非配置文件模式 | 支持传统的配置文件模式(配置文件),亦支持KV结构数据(配置项) | 使用配置文件的编程方式可能与程序员的编程习惯更为类似,更易于接受和使用。 |
编程模型 | 须要将配置文件拆成多个配置项,没有明显的编程模型 | 在使用配置文件的基础上,提供了注解式和基于XML的两种编程模型 | 无 |
并发性 | 多条配置要同时生效时,没法解决并发同时生效的问题 | 基于注解式的配置,能够解决并发性问题 | 无 |
</table>