---
title: 分布式配置中心详解：Apollo、Nacos、Spring Cloud Config 与 K8s ConfigMap 对比
description: 分布式配置中心原理与选型详解，涵盖 Apollo、Nacos、Spring Cloud Config、Kubernetes ConfigMap 的架构差异、配置推送机制、灰度发布、高可用设计和面试高频考点。
category: 分布式
keywords:
  - 配置中心
head:
  - - meta
    - name: keywords
      content: 配置中心,分布式配置中心,Apollo,Nacos,Spring Cloud Config,Kubernetes ConfigMap,配置推送,长轮询,灰度发布,配置中心面试题
---

## 为什么要用配置中心？

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

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

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

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

![Apollo 配置中心](https://oss.javaguide.cn/github/javaguide/config-center/view-release-history.png)

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

从分布式系统视角看，配置中心属于典型控制面：它负责决定“当前应该使用哪一份配置”，客户端负责拉取、缓存、监听和刷新。配置发布、灰度、回滚、客户端本地快照，处理的都是集中决策和客户端容灾之间的取舍。这个取舍可以和 [分布式协调详解](./protocol/centralized-and-decentralized.md) 放在一起理解。

配置中心还经常和 [RPC](./rpc/) 以及 [API 网关](./api-gateway.md) 一起出现：RPC 框架需要拿到服务地址、超时、重试、降级等治理配置，网关也可能依赖配置中心做动态路由和灰度规则。它们解决的问题不同，但在真实微服务体系里通常会连在同一条链路上。

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

| 方案                                                                | 状态       | 特点                                   |
| ------------------------------------------------------------------- | ---------- | -------------------------------------- |
| [Spring Cloud Config](https://cloud.spring.io/spring-cloud-config/) | 活跃       | Spring 生态原生支持，基于 Git 存储     |
| [Nacos](https://github.com/alibaba/nacos)                           | 活跃       | 阿里开源，配置中心 + 服务发现二合一    |
| [Apollo](https://github.com/apolloconfig/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。

| 功能点       | Apollo                                     | Nacos                                        | Spring 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 + JRaft | Git + 可选消息队列                   |

**深度对比**：

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](https://github.com/apolloconfig/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 官方使用指南](https://www.apolloconfig.com/#/zh/)。

### Apollo 架构解析

官方给出的 Apollo 基础模型（图片来源：Apollo 官方文档 - Apollo Design）：

![](https://img-blog.csdnimg.cn/a75ccb863e4a401d947c87bb14af7dc3.png)

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

官方架构图（图片来源：Apollo 官方文档 - Apollo Design）：

![](https://img-blog.csdnimg.cn/79c7445f9dbc45adb45699d40ef50f44.png)

### 组件说明

| 组件               | 作用                                                                                    | 默认端口               |
| ------------------ | --------------------------------------------------------------------------------------- | ---------------------- |
| **Portal**         | Web 管理界面，提供配置的可视化管理                                                      | 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 使用示例

获取配置：

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

监听配置变化：

```java
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` 目录为准。

## 参考

- [Nacos 官方文档](https://nacos.io/docs/latest/what-is-nacos/)
- [Nacos 集群模式部署](https://nacos.io/docs/v2.5/manual/admin/deployment/deployment-cluster/)
- [Apollo 官方文档](https://www.apolloconfig.com/#/zh/README)
- [Apollo GitHub 仓库](https://github.com/apolloconfig/apollo)
- [Spring Cloud Config 官方文档](https://cloud.spring.io/spring-cloud-config/)
- [Spring Cloud 版本兼容矩阵](https://spring.io/spring-cloud)
- [Kubernetes ConfigMap 官方文档](https://kubernetes.io/docs/concepts/configuration/configmap/)
- [Nacos 1.1.0 发布，支持灰度配置](https://nacos.io/zh-cn/blog/nacos%201.1.0.html)
- [Apollo 在有赞的实践](https://mp.weixin.qq.com/s/Ge14UeY9Gm2Hrk--E47eJQ)
- [微服务配置中心选型比较](https://www.itshangxp.com/spring-cloud/spring-cloud-config-center/)

<!-- @include: @planet.snippet.md -->
