我们知道,在程序中不应该把代码或流程写死,而应该把一些流程提取成开关、变量等。这样,就可以在不改变代码的情况下,在程序运行时执行不同的功能。这些开关、变量的集合一般放在一个或者多个文件里,称之为配置文件。一般来说,大部分程序都会存在这个文件,既然有文件,就需要管理。尤其是现在微服务化的趋势下,服务拆分,服务数量变多,配置文件的数量也跟着增加,就需要一个中心化的服务来管控这些配置文件,我们称之为配置中心,它一般会提供以下能力:
- 配置的集中化管理,统一标准。
- 配置的安全存储,不丢失。
- 下发配置到服务,并支持自动更新。
- 敏感配置的加密,权限管控。
- 高可用,配置中心作为系统的关键节点,必须保证可用性。
- 接入成本低,一般来说,刚开始以业务为主,对配置文件的管理需求没那么着急,等业务稳定才会考虑建立配置中心。那么,如何快速接入,快速切换,就很重要了。
那么,如何才能做好一个配置中心?下面列出几种可行的方案,并对比了其中的区别和优缺点。
### Git 配置中心
配置信息存到 Git,比如:Spring 的 ConfigServer。这种方式利用了 Git 的存储特性和保存历史提交的特性,开发量小,接入简单,架构图如下:
![git.png](https://static.golangjob.cn/221108/dadf77f8621838e281bb414c5448e151.png)
在写入端,管理员通过 `git push`推送配置到仓库,并且能通过 git 提供的历史提交、权限管理等功能,对配置进行集中化管理,企业的 git 仓库一般也都会备份,所以数据不容易丢失。
在获取端,git 的弊端就比较明显了,你不能直接在程序中访问 git 获取配置,只能用个服务做中转,它根据程序的元信息去 git 仓库取配置,也不支持自动更新(虽然可以利用 git webhook,但是中转服务如何通知到程序,还是个问题。)而且加密解密也只能做到中转服务里,发送给程序的配置文件是不能加密的,不然程序没办法读取。
最后,Git 本身是单点服务,要是升级个版本或者做些运维操作时候,把 git 服务器弄挂了,就没办法获取配置了。
总而言之,读者可以发现,如果使用 git,其实整个系统中最关键的节点是中转服务,也就是那个 ConfigServer,可是既然要满足一个配置中心的所有要求,需要对这个 ConfigServer 进行开发迭代,那还不如把配置文件存到 Mysql 里,Mysql 相对更稳定,运维经验成熟,也容易扩展一些。
### Apollo 配置中心
[Apollo](https://www.apolloconfig.com/#/zh/README) 就是这样做的,它没有依赖 git 去实现历史版本、权限等功能,全部由自己实现,它的架构图如下(从官网下载):
![apollo.png](https://static.golangjob.cn/221108/7715d9570675453a808d2791a9b2ec62.png)
Apollo 确实是配置中心的标杆级项目,基本实现了一个配置中心的所有该有的功能,也十分契合当今微服务化、分布式的趋势,无需吹嘘它的功能多么多么强大,明者自鉴。只需说它的一个最大缺点,这个缺点正是源自它众多的功能 --- 它太复杂了。
我们不说如上的架构图,一个新手能不能看懂。就说它提供的命名空间、集群、环境、注册中心等等概念,就不是一下子能快速上手的。而且这么多功能在它的管理后台上,老实说组织的确实比较乱,东一块西一块的,没有层级划分。
我感觉 Apollo 和 git 配置中心正好相反,git 配置中心架构简单,功能不丰富;Apollo 提供了所有的能力,架构也是非常复杂。
### Nacos 配置中心
随着云原生时代的来临,越来越多的组织在它们的技术架构中添加注册中心,以处理越来越多的微服务之间的发现和通信问题。[Nacos](https://nacos.io/zh-cn/) 就是开源的注册中心中的佼佼者,它在 2.0 版本中又增加了配置中心的功能,让配置中心和注册中心得以合并。
Nacos 的问题主要是它不是专注于配置中心,提供的功能相对比较薄弱。比如:只有 java 的客户端,其它语言客户端是社区贡献,文档方面会差一些;不支持配置的加密解密(新版本支持了,但是需要编译,工作量大);自动更新支持的不是很好等等。
Nacos 目前还在蓬勃发展,也是属于 Java 世界中配置中心的比较好的一个选择。
### 自研配置中心
最后剩下的一类,就是不使用开源方案,全自研。自研的好处就是可以适应内部项目,便于迭代和掌控。而且,配置中心说到底,也不是一个十分复杂的项目,自研起来并没有特别的难点。
自研的配置中心一般类似于 Apollo和 Nacos,通过 Mysql 来存储配置,并提供一个管理界面。可以理解为对这两个项目进行模仿和改造,虽然会有些不同,但殊途同归,基本上是差不了多少的。
这里还有一类自研的配置中心,用的不是 mysql 存储配置,而是 [ETCD](https://etcd.io/)。原因是 ETCD 提供的功能,和配置中心的需求重合性很高,天生就比较适合,自研起来工作量小,基本上,只需要开发个操作 ETCD 的配置的后台即可。我们把配置中心的六大需求一个个拉下来看:
- 配置的集中化管理,统一标准。
配置存在 ETCD,因为 ETCD 没有专门的配置中心后台,需要自己实现一个,做出来增删改查和权限管控,就基本可以了。
- 配置的安全存储,不丢失。
ETCD 作为 Kubernetes 的底层存储,安全性应该是很有保证了。
- 下发配置到服务,并支持自动更新。
V3版本支持 基于 grpc 的 Watch 机制,性能和可用性都有保证,可以实时更新配置。
- 敏感配置的加密,权限管控。
加密这块 ETCD 本身也不支持,需要开发。
- 高可用,配置中心作为系统的关键节点,必须保证可用性。
支持多节点部署,作为云原生时代的基础设施,相关运维的经验也比较丰富,可用性有保证。
- 接入成本低,一般来说,刚开始以业务为主,对配置文件的管理需求没那么着急,等业务稳定才会考虑建立配置中心。那么,如何快速接入,快速切换,就很重要了。
有各语言的 SDK,接入起来比较简单、
这里最难的就是高可用部署,如果自研,多节点数据一致性保证,包括后期的运维都是在重复造 ETCD 的轮子。配置中心本身的属性也决定了它不是被高频访问的应用,因此 ETCD 提供的并发能力完全已经足够了。
### Sail
[Sail](https://sail.hyy-yu.space) 是一款开源的配置中心,它是我在开发了多款配置中心的基础上,总结经验,最后写出的一个开源项目,实际上,它的架构核心正是 ETCD:
![sail-data-flow.png](https://static.golangjob.cn/221108/7feb73cb2172cf5b439c57726d589478.png)
它为 ETCD 提供了一个专业的配置中心管理界面,通过界面对配置进行增删改查,并且提供了sdk,简化接入 etcd 的步骤。从配置中心的六大能力块来看:
- 配置的集中化管理,统一标准。
通过 Web 管理界面管理,支持配置层级划分、公共配置、权限管理、配置增删改查、多种类型的配置等各种功能。
- 配置的安全存储,不丢失。
正如上面所说,基于 ETCD 的 Sail,无需开发数据安全、一致性保证等功能,ETCD 本身会提供。
- 下发配置到服务,并支持自动更新。
封装 ETCD 的 SDK,提供更简单的接入。
- 敏感配置的加密,权限管控。
源头上支持加密,ETCD 存储的就是加密信息。在 SDK 中解密。解密秘钥可以通过环境变量等方式传递,环境变量可以通过 Jenkins 等发布系统注入,全程秘钥可以不公开,运行时才解密,保证了配置的安全性。
- 高可用,配置中心作为系统的关键节点,必须保证可用性。
可用性也是通过 ETCD 保证,ETCD 的部署节点越多,则越安全。但官方建议,不要超过 7 个。
- 接入成本低,一般来说,刚开始以业务为主,对配置文件的管理需求没那么着急,等业务稳定才会考虑建立配置中心。那么,如何快速接入,快速切换,就很重要了。
提供 golang SDK ,go 项目接入起来无任何压力。
其它语言项目,需要通过 ETCD 提供的语言相关客户端处理。
同时,Sail 还在全力开发 配置发布管理 和 监控指标输出 功能,这是 Sail 的最后两块拼图。
通过发布管理,可以控制自动更新时的策略,是按比例推送,还是先推指定节点等。
监控指标输出,则是对接 Prometheus,完善配置中心的可观察性。
### 总结
最后,引用那句经典的“软件开发里没有银弹”,我想补充一句:“你要知道你手里有哪些类型的子弹。”通过对比和分析,来确定当时,当地,最适合项目的那个方式,比如项目着急上线,先直接把配置文件写死在代码里,都不是不可以的,后期可以再改。如何做好一款配置中心?希望看完本文你能有自己的答案。
有疑问加站长微信联系(非本文作者))