随着公司的发展,团队成员和项目数越来越多,系统架构不可避免的要向系统安全和开发运维的成本等方面倾斜。毕竟过了小米加步枪的高速发展阶段,我们必须要鸟枪换炮,将系统的质量提高一个层级。
需求
绝大多数项目都离不开包含私密信息的配置文件,这些配置信息之前是分散在数以百计的项目中。不但管理起来麻烦,而且配置信息都放在项目中不可避免的存在安全隐患。我们经过分析研究,发现很多项目的配置都存在共性,如数据库的配置,日志的输出,ZK服务器的地址等等。虽然在maven中有阿里的auto-config插件,在安全性方面有所提升。但是由于该插件只能工作在maven,不能用于gradle等构建工具,并且每个项目还要按照要求编写模板。所以我们需要代码和配置完全分离,不依赖于任何的构建工具,项目代码中只有代码逻辑。
由于我们有些项目中的配置还需要实时的变动,并同步到所有机器,写死在配置文件中,那么服务就必须要重新启动,当然通过JMX或者通过服务调用来修改都行,但是如果服务集群较多,就会存在不小的工作量。所以我们需要希望我们的配置有发布订阅的功能。
最后所有的配置信息集中存储,统一管理,各个项目中不再需要配置文件。开发人员只需要关心业务,配置全交给运维人员,并且如果配置如果出现异常,可以快速回滚。
设计
需求明确了之后,我们将所有的项目进行了梳理,所有的配置信息类型可以归纳为下图:
从上图,我们可以看出其实我们的配置就是一个4层的文件夹。配置的存储,ZooKeeper当然是不二的选择。原因如下:
- ZK本来就是我们基础设施中不可获取的一环。
- 配置信息的结构和ZK的功能设计完全契合。
- 事件通知ZK天生就支持。
- ZK的高可用。
在做架构时,我们必须要保证系统能够平滑升级,将老系统升级的风险降到最低。我们发现90%的老系统都使用了spring框架,并且这些系统中90%的配置都是由spring加载。所以代码层面的切入点就非常明确了,分为如下两步:
- 包装一个ZK的工具类ZKUtils,实现读取ZK的配置和订阅文件的变化。
- 扩展
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
,让其能够从ZK读取配置。
技术细节
在技术的实现上,我们遵循Convention Over Configuration(约定优于配置),下面以一个名为Test的项目作为案例来说明。
配置的级别 | 路径 |
---|---|
Global | /Global/Properties/Test |
Project | /Global/Project/Properties/Test |
Server | /Global/Project/Server/Properties/Test |
Process | /Global/Project/Server/{进程标识如端口号}/Properties/Test |
项目名称也约定配置在classpath下的一个文件中,该项目名称会用在所有的内部框架中,如日志的输出文件名,配置文件的路径,监控中心的名称等等。
ZKUtils的实现就不说了,直接使用Curator稍微封装下,就能够满足需求。
PropertyPlaceholderConfigurer的实现类就直接贴代码了,都很简单。
1 | /** |
配置的使用如下
1 | "1.0" encoding="UTF-8" xml version= |
上面就是我在设计这个集中式配置中心的时候的一些想法,当然代码的具体实现比这个复杂多了,我只是捡最重要的说,是想把一个比较复杂的东西简单化。其实里面还有很多的容错机制,比如ZK集群宕机怎么办,是否可以读取本地的缓存等等。