# 统一配置中心

从单体架构与SOA转向微服务，配置中心这个服务可能会有些陌生，尤其是单体架构，几乎不存在这样的需求。

![](https://raw.githubusercontent.com/gudaoxuri/Microservices-Architecture/master/resources/images/ms-services-config1.png)

回顾我们以前变更配置的方式：修改各节点的配置文件，如果有多实例的话需要一个个节点地修改，修改后分批次重启或重载服务。这一做法在之前的架构中没有太大的问题，但考虑我们车贷通的场景，车贷通只是个中小型系统，它已有30个左右的服务，如果加上HA（高可用）服务实例起码需要\*2，即60多个服务实例，如果我们需要修改较为全局性的诸如数据库连接地址那将是个浩大的工程。

既然这样，那我们自然而然会想到将所有配置放到一个地方，比如最简单的，使用NAS共享存储，然后将配置分割成全局配置和服务自身的配置，如下图：

![](https://raw.githubusercontent.com/gudaoxuri/Microservices-Architecture/master/resources/images/ms-services-config2.png)

这一做法解决了集中化配置的问题，但如果NAS故障了呢？这个好办，我们可以对NAS做集群化或是使用云厂商的对象存储服务，而这就是配置中心的雏形，当然在生产中我们还有很多其它的要求。

我们可以发散下配置中心所能解决的问题场景有哪些，比如说线上问题排查，生产日志一般都是INFO级别的，但如果出现问题需要排查时传统的做法是修改成DEBUG后重启服务，但这一过程可能会导致环境变更而无法重现问题，所以最好的方法是结合配置中心实现在不重启服务的情况一下动态地变更日志级别，再比如容灾处理，成规模的公司都是混合云架构，应用上云，数据在自己的IDC，IDC一般都是异地多活，数据库多为主从方案（当然也类似Percona集群的方案，但有一定的问题） 程序上会做读写分离，在主库故障时我们需要配置中心可以快速地完成从库转主库的切换，还如活动管理，做ToC的公司会经常性地做一些营销活动，在活动大促期间对系统的负载、质量的保障都要高于平常，对应的会有一些特殊的配置（连接池、队列、线程、降级等），配置中心要能实现针对不同活动的配置管理。

所以我们期望的配置中心是可以将我们散落在各个地方（数据库、本地配置文件、启动参数、JNDI等）的配置进行统一的管理，而这里所谓的配置一般而言要求是可以用K-V形式表述，这意味着类似logback.xml、Groovy/JS动态脚本、多媒体文件等不适合使用配置中心管理。

明确了适用场景后我们可知真正可用于生产的配置中心会不可避免地需要考虑版本化、变更审计等问题，试想如果我们修改了全局的配置出现问题需要回滚，这时如果没有备份之前的配置那可能就会演变成一次生产事故，如果没有变更审计我们甚至在出问题后都无法追责。

配置中心的配置要有依赖继承关系，要分可环境或场景，比如常规的要有针对开发、测试、预发、生产等环境的特殊配置，也要有能针对诸如双11、618大促等活动的特殊配置，微服务下每个服务都有自身的配置，但也有公共的配置，公共配置应该可以统一设置，在获取某个微服务配置时配置中心会自动合并要求环境及场景下的公共配置、服务自身配置。

![](https://raw.githubusercontent.com/gudaoxuri/Microservices-Architecture/master/resources/images/ms-services-config3.png)

我们再考虑下这么多服务，难道改配置后需要一个个实例地重启，显然这是不合适的，配置中心要求可以动态地刷新并应用新的服务配置，并且要支持分批次或灰度发布，即可以按指定的策略先刷新一批服务实例，如没有问题后再全网刷新，当然这两个特性都需要服务自身提供相应的支持，比如配置刷新，一般会在服务中加入配置中心的SDK，SDK收到新配置后通知服务实现重载配置，但诸如数据库连接池等有缓存设计的功能需要服务自身处理配置的更新逻辑，分批次或灰度发布可以是按随机百分比更新，也可以按高级规则处理，后者要求我们的服务实例能给出对应的标签，比如我们的路由策略是按地域分发的，那么对应的不同服务实例可以带上地域标签，这时就可以按地域实现批次或灰度更新。

一个优秀的配置中心还需要做到弱依赖，即脱离配置中心各服务依然可以运行，最常规的做法是服务在启动时向配置中心获取配置并缓存到本地，配置中心推送配置或服务定时主动拉取最新的配置并更新缓存，在配置中心或对应的网络故障时各服务可正常运行。

上面这样就是我们所谓配置中心的关键要求，总结一下，配置中心的设计核心有：

* **集中化管理与配置切片** 所有配置可以统一管理，配置可以按一定的维度切片，常见的按作用域分为全局级与服务级、按环境分为生产、预发、测试、开发等、按场景分各类特殊的活动
* **版本化与变更审计** 所有配置变更要保留历史版本、记录操作人员以便回滚与审计，最简单的是使用GIT方式
* **动态刷新** 配置可以按一定策略动态刷新，在有服务依赖的情况下先刷新被依赖的服务，在有多实例的情况下实现按批次或灰度刷新，仅在上一次刷新成功后再人式或自动地刷新其它实例，当然这需要有SDK配合使用
* **高可用** 配置中心自身要足够健壮，并且配置中心最好也可以当成一个普通服务注册到注册中心形成统一的整体
* **弱依赖** 各服务在运行期间不应强依赖配置中心，做好配置获取及缓存策略，在配置中心或网络故障时使用缓存配置，在正常后刷新本地缓存
* **Push/Pull** 配置更新的方式有Push或Pull两种，Push对配置变更的感知实时性高，但同时对配置中心的要求也更高
* **SDK支持** 配置中心要有对应的SDK以实现配置的刷新、缓存，确保即便是配置中心宕机或网络不通时不会影响服务本身的运行

配置中心置于微服务是重要的核心服务之一，市面上有诸如Spring Cloud Config这一与Spring Cloud配套的配置中心，也有如百度开源的Disconf、国内携程开源的Apollo 等比较成熟的独立配置中心。

如果是Spring Cloud项目，那么一般情况下Spring Cloud Config即可满足要求，反之可以考虑Apollo，一些特殊的情况也可以考虑基于Etcd进行定制化开发。
