随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址……
对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制……
在这样的大环境下,传统的通过配置文件、数据库等方式已经越来越无法满足开发人员对配置管理的需求。
统一配置管理中心能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。
按照我们的理解,配置有以下几个属性:
- 配置是独立于程序的只读变量
- 配置首先是独立于程序的,同一份程序在不同的配置下会有不同的行为。
- 其次,配置对于程序是只读的,程序通过读取配置来改变自己的行为,但是程序不应该去改变配置。
- 常见的配置有:DB Connection Str、Thread Pool Size、Buffer Size、Request Timeout、Feature Switch、Server Urls等。
- 配置伴随应用的整个生命周期
- 配置贯穿于应用的整个生命周期,应用在启动时通过读取配置来初始化,在运行时根据配置调整行为。
- 配置可以有多种加载方式
- 配置也有很多种加载方式,常见的有程序内部hard code,配置文件,环境变量,启动参数,基于数据库等
- 配置需要治理
- 权限控制
- 由于配置能改变程序的行为,不正确的配置甚至能引起灾难,所以对配置的修改必须有比较完善的权限控制
- 不同环境、集群配置管理
- 同一份程序在不同的环境(开发,测试,生产)、不同的集群(如不同的数据中心)经常需要有不同的配置,所以需要有完善的环境、集群配置管理
- 框架类组件配置管理
- 还有一类比较特殊的配置 - 框架类组件配置,比如CAT客户端的配置。
- 虽然这类框架类组件是由其他团队开发、维护,但是运行时是在业务实际应用内的,所以本质上可以认为框架类组件也是应用的一部分。
- 这类组件对应的配置也需要有比较完善的管理方式。
- 权限控制
比较业内配置中心动态配置即时生效的设计方案,大致有如下三种:
- HTTP长连接
- TCP长连接
- 依赖第三方中间件产品zookeeper
比较来看:HTTP长连接方案,其本质仍然是Request-Response交互模型,是通过长轮询等方式实现的伪长连接,另外轮询会对服务端产生一定的压力;基于传输层的TCP长连接方案因为有了Java NIO并借助Netty、Mina这样的框架实现,效果及优势比较明显,但是有一定的学习门槛和开发难度;借助zookeeper实现的推模型,客户端通过watch监听结节,更新比较方便,但是缺点也比较明显:大量连接时,zookeeper压力比较大、跨机房同步问题、权限管理。
综合来看,采用基于TCP长连接的消息中间件来实现配置中心的动态配置功能比较好,学习门槛较低且不失性能,另外典型的“发布者—订阅者”模型易于管理和理解。
对比项目 | diamond | configserver | disconf | apollo |
---|---|---|---|---|
配置存储 | 存储在mysql上 | 维护在内存中,非持久化 | 存储在mysql上 | 存储在数据库上 |
推拉模型 | 基于HTTP长轮询的拉模型,准实时推送 | 基于TCP长连接的推模型 | 基于zookeeper的推模型,实时推送 | 基于HTTP长轮询的拉模型,准实时推送,另有一个5min的异步补偿任务定时拉取配置 |
配置读写 | 支持实例对配置读写;支持某台实例写配置数据,并广播到其他实例上 | 基于TCP长连接的配置注册和失效机制 | 只支持实例对配置读。通过在disconf-web上更新配置 | 只支持实例对配置读。提供Web界面供用户管理配置 |
容灾 | 多级容灾模式,配置数据会dump在本地,避免中心服务器挂机时无法使用 | 多级容灾模式,优先读取本地配置文件 | 多级容灾模式,服务不可用时读取缓存在本地文件系统中的配置 | |
配置数据模型 | 只支持KV结构的数据,非配置文件模式 | 支持配置文件模式、支持KV结构数据 | 基于application.environment.cluster.namespace四级定位的KV结构 | |
功能特性 | 需要地址服务器,客户端连接到地址服务器,取回diamond服务器端地址列表 | configserver已经定位为注册中心,TCP连接建立时新增注册中心配置项,连接断开时注销注册中心配置项 | 对配置进行持久化管理并对外提供RESTful接口注解式编程支持配置的上传、下载支持分布式环境下的主备竞争 | 实现了不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)下配置的统一管理 |
数据同步 | 基于数据库和本地文件server写数据时,先将数据写入mysql,然后写入本地文件client订阅数据时,访问的是本地文件,不查询数据库,这样即使数据库出问题,仍然不影响client的订阅 | 基于zookeeper实现对配置更改的实时推送全局分布式一致性锁来实现主备统一部署、系统异常时代主备自主切换 | 客户端从apollo配置中心服务端获取到应用最新配置后,会保存在内存中。客户端会把获取到的配置在本地文件系统缓存一份,遇到服务不可用,依然能从本地恢复 | |
优点 | 简单、可靠、易用 | 基于TCP长连接实现实时推送功能,基于传输层协议实现性能更高。 | 基于分布式的zookeeper来实时推送 | 服务端使用Spring DeferredResult实现异步化,从而大大增加长连接数量 |
缺点 | 无访问修改权限控制不支持对于基于SOA架构的服务注册发现 | 数据非持久化,仅适用于注册中心等场景,不适合配置中心式的管理方式。 | 依赖zookeeper的推送机制 | 应用层协议实现,依然是轮询机制 |
使用案例 | 淘系绝大多数系统 | 服务于阿里内部HSF等需要服务注册的场景 | 百度、滴滴、网易、苏宁易购等 | 携程等 |
待补充。