distributed-configuration-center.md

May 25, 2026 · View on GitHub

为什么要用配置中心?

微服务架构下,应用被拆分为大量独立部署的服务,每个服务都有自己的配置(服务地址、数据库参数、功能开关等)。配置项数量会随着服务数量、环境数量和集群数量一起增长。传统配置文件方式存在以下问题:

  • 修改需重启:无论配置在代码库还是外部文件中,很多应用都需要重启进程才能让新配置生效。
  • 与发版耦合:如果配置放在代码库中,配置变更往往要跟代码发版绑定,难以独立灰度和回滚。
  • 安全性不足:敏感配置(数据库密码、API Key)直接写在代码库中容易泄露。
  • 缺乏权限控制:无法对配置的查看、修改、发布等操作进行细粒度权限管控。
  • 配置分散难管理:多环境(开发/测试/生产)、多集群的配置分散在各处,难以统一维护。

此外,配置中心通常提供以下增强能力:

  • 版本管理:记录每次配置变更的修改人、修改时间、修改内容,支持一键回滚。
  • 灰度发布:先将配置推送给部分实例验证,降低变更风险(Apollo、Nacos 1.1.0+ 支持)。

Apollo 配置中心

当然,不是所有系统都需要上配置中心。单体应用、单环境、配置项很少且变更频率低的场景,application-{profile}.yml、环境变量或 Kubernetes ConfigMap + 滚动重启通常就够了。配置中心会带来额外的运维成本、故障域和排查链路,小团队或低频配置场景不必过度工程化。

常见的配置中心有哪些?如何选择?

方案状态特点
Spring Cloud Config活跃Spring 生态原生支持,基于 Git 存储
Nacos活跃阿里开源,配置中心 + 服务发现二合一
Apollo活跃携程开源,配置管理、权限和审计能力较强
K8s ConfigMap活跃Kubernetes 原生方案
Disconf / Qconf长期不活跃不建议新项目使用

选型建议

  • 只需配置中心 → Apollo(管理能力更细)或 Nacos(单机启动更轻)
  • 需要配置中心 + 服务发现 → Nacos
  • Spring Cloud 体系且追求简单 → Spring Cloud Config
  • Kubernetes 环境 → K8s ConfigMap 挂载 + 应用层文件监听。ConfigMap 以 Volume 挂载时会被 kubelet 周期同步,最终可见时间取决于 kubelet 同步周期和本地缓存传播方式;环境变量方式和 subPath 挂载不会自动更新。热重载可以用 inotify 监听挂载文件,也可以用 Spring Cloud Kubernetes 通过 K8s Watch API 监听 ConfigMap 变更并触发刷新。

Apollo vs Nacos vs Spring Cloud Config

版本说明:以下对比基于 Apollo 2.x、Nacos 2.x、Spring Cloud Config 4.x/5.x。Spring Boot 3 体系通常对应 Spring Cloud Config 4.x,Spring Boot 4 体系对应更新的 Spring Cloud 2025.x 发行列车;如果仍在 Spring Boot 2 体系,对应的是 Spring Cloud Config 3.x。

功能点ApolloNacosSpring Cloud Config
配置界面支持(权限、审计、发布流程较完整)支持无(通常通过 Git 平台操作)
配置实时生效支持(HTTP 长轮询,通常秒级感知)支持(gRPC 变更通知 + 客户端拉取)半实时(需触发 refresh 或 Bus 广播)
版本管理原生支持原生支持依赖 Git
权限管理支持(应用/命名空间/环境等多层粒度)支持依赖 Git 平台
灰度发布支持(规则更细)支持(1.1.0+,能力相对基础)不支持
配置回滚支持支持依赖 Git
告警通知支持支持不支持
多语言支持(Open API / 多语言客户端)支持(Open API / 多语言客户端)更偏 Spring 应用
多环境支持(通常物理隔离)支持(多用 Namespace 逻辑隔离)需配合多 Git 仓库
依赖组件MySQL(注册中心默认内嵌在 Config Service)外部 MySQL(生产推荐)/ 嵌入式 Derby + JRaftGit + 可选消息队列

深度对比

  1. Apollo:在权限模型、发布审计、发布前 diff、灰度规则等管理特性上更细,适合对配置治理要求较高的团队。多环境(FAT/UAT/PROD)物理隔离场景下,需为每个环境部署 Config Service、Admin Service 和独立数据库,运维门槛中等偏高
  2. Nacos:配置 + 注册中心二合一,部署简单(单机模式仅一个 Jar 包)。生产集群推荐使用外部 MySQL;嵌入式 Derby + JRaft 更适合测试或小规模场景。Nacos 的 Namespace/Group/DataId 模型上手快,但环境隔离通常偏逻辑隔离
  3. Spring Cloud Config:架构最简单(基于 Git),但实时性差,需要额外组件实现自动刷新

配置中心、注册中心与 K8s ConfigMap 的边界

  • 应用配置中心(Apollo/Nacos/Spring Cloud Config):主要解决业务参数、开关、阈值、连接信息等应用配置的集中管理、审计、灰度和动态刷新。
  • 服务注册中心(Eureka/Nacos/Consul):主要解决服务实例注册、发现和健康状态同步。Nacos 同时提供配置中心和注册中心能力,但两类职责仍然不同。
  • Kubernetes ConfigMap:主要解决 Pod 启动参数、环境变量、挂载文件等容器运行时配置管理,不天然提供发布审批、灰度规则和应用内对象刷新。
  • Service Mesh / Ingress 配置:主要解决流量路由、熔断、重试、超时、灰度流量等治理策略,配置对象通常是 CRD 或控制平面资源。

配置中心核心设计要点

设计或选型配置中心时,需关注以下能力:

1. 配置推送机制

模式实时性服务端压力实现复杂度适用场景
推模式高(毫秒级)高(需维护连接)强实时性要求
拉模式低(秒~分钟级)高(无效轮询)配置变更极少
长轮询中高(秒级)中等(海量连接时内存压力大)主流方案

推送机制说明

  • Apollo:采用 HTTP 长轮询。客户端发起请求,服务端若有变更立即返回;无变更则挂起请求(服务端默认约 60s,客户端 read timeout 通常更长),期间一旦有变更立即响应。
  • Nacos 2.x:服务发现链路升级为 gRPC 双向流,实时性更好;配置中心链路更准确地说是“变更通知 + 客户端拉取”的两阶段模型,服务端通知配置发生变化,客户端再按需拉取最新配置内容。

注意:严格说,长轮询仍是客户端发起的拉取请求,只是服务端通过挂起请求实现近实时;本表按行业惯例将其单列以突出运行特征。长轮询虽然比短轮询节省 CPU 和网络开销,但当客户端规模达到十万级时,服务端仍需维持海量挂起请求。以 Apollo 为例,服务端基于 Spring MVC DeferredResult 挂起请求,底层依托 Servlet 3.0 异步特性和 Tomcat NIO Connector 承载,对内存和连接数上限仍有要求。

2. 必备功能清单

  • 权限控制:配置的查看、修改、发布需分级授权
  • 审计日志:完整记录配置变更的操作人、时间、内容
  • 版本管理:每次发布生成版本号,支持回滚到任意历史版本
  • 灰度发布:配置先推送到部分实例,验证通过后全量发布
  • 多环境隔离:开发、测试、生产环境配置独立管理
  • 高可用部署:配置中心自身需要集群化部署,避免单点故障

3. 客户端容灾与启动顺序

配置中心是基础设施,一旦不可用会影响大量业务应用。因此客户端必须具备容灾能力:

  • 多级缓存:优先读内存配置;配置中心不可用时读取本地快照;本地快照也不存在时使用代码里的兜底默认值或拒绝启动。
  • 降级启动:对于非关键配置,可以先用本地快照启动,再异步连接配置中心;对于数据库地址、加密密钥这类关键配置,可以选择“无配置不启动”。
  • 断线重连:长轮询或长连接断开后,客户端应带退避策略重连,避免配置中心恢复时被瞬时流量打满。
  • 刷新边界:动态刷新不等于所有对象都会自动改变。比如 Spring 中已注入到普通字段、final 字段或条件装配逻辑里的值,可能不会按预期刷新,需要配合 @RefreshScope、监听器或重新设计 Bean 生命周期。

以 Apollo 为例介绍配置中心的设计

Apollo 介绍

根据 Apollo 官方介绍:

Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

服务端基于 Spring Boot 和 Spring Cloud 开发,打包后可以直接运行,不需要额外安装 Tomcat 等应用容器。

Java 客户端不依赖任何框架,能够运行于所有 Java 运行时环境,同时对 Spring/Spring Boot 环境也有较好的支持。

Apollo 核心特性:

  • 配置修改实时生效(热发布):基于长轮询,1s 内即可接收到最新配置
  • 灰度发布:配置只推给部分应用,降低变更风险
  • 部署简单:单环境仅依赖 MySQL;Apollo 自带的注册中心(默认为 Eureka)以内嵌方式运行于 Config Service 进程内,无需独立部署。多环境物理隔离时,需要为每个环境部署一套 Config Service、Admin Service 和独立数据库
  • 跨语言:提供了 HTTP 接口,不限制编程语言

关于如何使用 Apollo 可以查看 Apollo 官方使用指南

Apollo 架构解析

官方给出的 Apollo 基础模型(图片来源:Apollo 官方文档 - Apollo Design):

  1. 用户在 Apollo 配置中心修改/发布配置
  2. Apollo 配置中心通知应用配置已更改
  3. 应用访问 Apollo 配置中心获取最新配置

官方架构图(图片来源:Apollo 官方文档 - Apollo Design):

组件说明

组件作用默认端口
PortalWeb 管理界面,提供配置的可视化管理8070
Client客户端 SDK,提供配置获取和变更监听能力-
Meta Server服务发现入口,与 Config Service 同进程,供 Client/Portal 获取服务地址8080
Config Service提供配置读取和长轮询通知接口,供 Client 调用;同时内嵌注册中心8080
Admin Service提供配置管理接口,供 Portal 调用8090
Eureka(内嵌)Config Service 同进程内嵌的注册中心实例,供 Config/Admin Service 注册发现;无需独立部署与 Config Service 相同
MySQL存储配置数据和元数据3306

Apollo 2.0+ 支持通过 SPI 替换服务注册发现实现,例如接入 Nacos、Consul、Polaris 等。但在默认部署模型下,Eureka 是 Config Service 内嵌能力,不应把它理解为需要单独运维的外部 Eureka 集群。

核心流程

Client 端(获取配置)

  1. Client 启动时访问 Meta Server 获取 Config Service 地址列表
  2. Client 本地缓存服务地址(Eureka 故障时仍可用)
  3. Client 发起长轮询请求获取配置
  4. Config Service 检测到配置变更后立即响应
  5. Client 更新内存缓存、触发变更回调,并异步持久化到本地文件系统。Linux/Mac 默认缓存目录位于 /opt/data/{appId}/config-cache/,Windows 默认位于 C:\opt\data\{appId}\config-cache\,也可以通过系统属性 apollo.cache-dir 自定义

灾备机制:即使 Config Service 全部宕机且应用重启,Client 仍可从本地磁盘读取缓存的配置完成启动,确保应用可用性不强依赖配置中心。

Portal 端(发布配置)

  1. 用户在 Portal 修改配置并点击发布
  2. Portal 调用 Admin Service 发布接口
  3. Admin Service 将配置写入 MySQL 并生成发布版本
  4. Config Service 通过长轮询通知 Client 配置已变更
  5. Client 重新拉取最新配置

Client 使用示例

获取配置:

Config config = ConfigService.getAppConfig();
String someKey = "someKeyFromDefaultNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);

监听配置变化:

Config config = ConfigService.getAppConfig();
config.addChangeListener(new ConfigChangeListener() {
    @Override
    public void onChange(ConfigChangeEvent changeEvent) {
        // 处理配置变更
        for (String key : changeEvent.changedKeys()) {
            ConfigChange change = changeEvent.getChange(key);
            System.out.println(String.format(
                "Key: %s, Old: %s, New: %s",
                key, change.getOldValue(), change.getNewValue()));
        }
    }
});

在 Spring Boot 项目中,生产代码通常不会直接到处调用底层 API,而是通过 Apollo Spring 集成完成配置注入和刷新,例如使用 @EnableApolloConfig 启用 Apollo,通过 @Value@ConfigurationProperties@ApolloConfigChangeListener 监听变更。需要注意的是,条件装配类(例如 @ConditionalOnProperty)和已经初始化完成的复杂 Bean 不一定会因为配置变化自动重建,关键配置变更仍要结合业务刷新策略验证。

Nacos 配置中心核心模型

Nacos 同时提供配置中心和服务发现能力,这也是它与 Apollo 的主要差异之一。从配置中心角度看,Nacos 常用三层模型来定位一份配置:

  • Namespace:通常用于环境或租户隔离,例如 dev、test、prod。
  • Group:通常用于业务域或应用分组,默认是 DEFAULT_GROUP
  • DataId:具体配置文件或配置项标识,例如 order-service.yaml

Nacos 的配置存储也要区分部署形态:

  • 生产集群:推荐使用外部 MySQL 存储配置数据,数据一致性主要由 MySQL 自身的高可用方案保障。
  • 嵌入式存储:Nacos 也支持 Derby 等嵌入式存储。集群模式下,Nacos 通过 JRaft 将各节点的嵌入式存储组成逻辑集群,适合测试、小规模或对运维成本特别敏感的场景,但排障复杂度更高。

Nacos 2.x 引入 gRPC 长连接后,客户端与服务端之间的连接开销比 1.x HTTP 长轮询更低。配置变更时,服务端会通知客户端“某个配置发生变化”,客户端再拉取最新配置内容并回调监听器。这样可以避免把大配置内容直接塞进通知链路,也便于客户端做本地快照和容灾。

Nacos 客户端同样会维护本地快照。配置中心不可用时,客户端可以读取本地 snapshot/failover 文件继续启动或运行;具体缓存路径会随客户端版本、命名空间、服务端地址、Group 和 DataId 变化,排障时建议以目标版本客户端日志和本地 nacos/config 目录为准。

参考