工程实践 工程实践

Apollo 配置中心:携程开源的银行级配置管理平台

从架构设计、多环境隔离、灰度发布、权限管控到 Spring Boot 集成,详解 Apollo 在银行生产环境中的完整落地,包括与 Nacos 的选型对比和 Kubernetes 部署实战。

发布于 2026/03/22 更新于 2026/03/22 2 分钟

“Nacos 配置中心轻量好用,Apollo 配置中心功能更全。Apollo 的灰度发布、配置审计、多语言客户端、推送失败告警,是大型银行多团队协作时的刚需。“

前言

Apollo(Apollo GraphQL/配置中心)是携程开源的配置管理平台,在银行系统中有大量部署。相比 Nacos,Apollo 的核心优势在于:

  • 灰度发布:配置可以先对 10% 的实例生效,观察无异常后再全量
  • 配置回滚:所有历史版本可追溯,可一键回滚到任意版本
  • 多语言 SDK:Java/.NET/Go/Python/Node.js,异构系统统一管理
  • 发布审批流:支持多级审批,生产发布需要 Team Lead 审批
  • 告警通知:推送失败、配置泄漏、访问异常可实时告警

银行场景典型选择:

  • 小团队 + 简单需求 → Nacos(轻量,学习曲线平缓)
  • 大银行 + 多团队 + 强合规 → Apollo(审计完整,权限精细)

1. Apollo 架构

Apollo 架构(核心组件):

┌──────────────────────────────────────────────────────────────┐
│                    Apollo Portal(Web 管理界面)                │
│    环境管理 | 命名空间 | 应用管理 | 灰度发布 | 权限配置          │
│    端口: 8070                                                │
└────────────────────────────┬─────────────────────────────────┘
                             │ HTTP / gRPC
         ┌───────────────────┼────────────────────┐
         ▼                   ▼                    ▼
┌────────────────┐  ┌────────────────┐  ┌────────────────┐
│ Config Dev     │  │ Config UAT     │  │ Config Prod    │
│ :8080          │  │ :8080          │  │ :8080          │
└────────┬───────┘  └────────┬───────┘  └────────┬───────┘
         │                  │                    │
         └──────────────────┼────────────────────┘
                            │ Config Service(配置读取/写入)

┌─────────────────────────────────────────────────────────────┐
│                      Meta Server(Eureka/Zookeeper)            │
│              服务注册与发现:Portal、Config Service、Admin Service │
└────────────────────────────┬────────────────────────────────┘

         ┌───────────────────┼────────────────────┐
         ▼                   ▼                    ▼
┌────────────────┐  ┌────────────────┐  ┌────────────────┐
│   MySQL Dev    │  │   MySQL UAT   │  │  MySQL Prod   │
│ (配置存储)    │  │  (配置存储)   │  │  (配置存储)   │
└────────────────┘  └────────────────┘  └────────────────┘

Apollo 客户端工作流程:
  ① Client 启动 → 连接 Meta Server → 找到 Config Service
  ② Config Service 返回配置 → Client 缓存到本地
  ③ 启动长轮询(每 5 秒)→ 检测配置变化
  ④ 变化时 → Config Service 推送新配置 → Client 回调 Application 监听器

1.2 核心概念

Apollo 四层概念:

应用(App)→ 环境(Env)→ 集群(Cluster)→ 命名空间(Namespace)

示例:
  App: payment-service(支付服务)
    ├── Env: DEV
    │     ├── Cluster: default
    │     │     └── Namespace: application(应用私有配置)
    │     │     └── Namespace: db-config(共享数据库配置)
    │     └── Cluster: hk-datacenter
    ├── Env: UAT
    └── Env: PROD
          ├── Cluster: default
          └── Cluster: disaster-recovery(灾备集群)

2. Kubernetes 集群部署

2.1 组件概览

Apollo 包含 5 个组件:
  apollo-configservice    # 配置服务,客户端连接此服务获取配置
  apollo-adminservice    # 管理服务,Portal 通过此服务写入配置
  apollo-portal          # Web 管理界面
  apollo-meta-server     # 元数据服务(可选,用 Eureka 代替)
  apollo-dbconverter    # 导入工具(一次性使用)

2.2 Helm 部署

# apollo-helm/values.yaml
portal:
  replicaCount: 2
  image:
    repository: apolloconfig/apollo-portal
    tag: "2.2.0"
  service:
    type: ClusterIP
    port: 8070
  ingress:
    enabled: true
    className: nginx
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
    hosts:
      - apollo.bank.internal
  env: 'PRO'
  adminmanservices: 'apollo-adminservice'
  configmanservices: 'apollo-configservice'

config:
  replicaCount: 2
  image:
    repository: apolloconfig/apollo-configservice
    tag: "2.2.0"
  env: 'PRO'
  configDb:
    host: ${APOLLO_MYSQL_HOST}
    port: 3306
    dbName: ApolloConfigDB
    user: apollo
    password: ${APOLLO_DB_PASSWORD}
  resources:
    requests:
      cpu: 1000m
      memory: 1Gi
    limits:
      cpu: 2000m
      memory: 2Gi

admin:
  replicaCount: 2
  image:
    repository: apolloconfig/apollo-adminservice
    tag: "2.2.0"
  env: 'PRO'
  configDb:
    host: ${APOLLO_MYSQL_HOST}
    port: 3306
    dbName: ApolloConfigDB
    user: apollo
    password: ${APOLLO_DB_PASSWORD}

2.3 MySQL 初始化

-- Apollo 需要两个数据库
CREATE DATABASE ApolloConfigDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE ApolloPortalDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 执行初始化脚本(Apollo 发布包中自带)
-- https://github.com/apolloconfig/apollo/releases
mysql -u apollo -p ApolloConfigDB < apolloconfigdb.sql
mysql -u apollo -p ApolloPortalDB < apolloportaldb.sql

3. Spring Boot 集成

3.1 客户端接入

<dependency>
    <groupId>com.ctrip.framework.apollo</groupId>
    <artifactId>apollo-client</artifactId>
    <version>2.4.0</version>
</dependency>
# bootstrap.yml(Apollo 配置)
apollo:
  bootstrap:
    enabled: true   # 启动时加载 Apollo 配置(必须开启)
    namespaces: application,db-config  # 加载多个命名空间

  # Meta Server 地址(生产至少两个节点)
  meta:
    # 格式:${ENV}_meta(Apollo 自动替换)
    dev: http://apollo-meta-dev.bank.internal:8080
    pro: http://apollo-meta-prod.bank.internal:8080

  # 应用信息
  app:
    id: payment-service   # Apollo Portal 中创建的应用 ID

  # 集群(可按机房分配)
  cluster: ${APOLLO_CLUSTER:default}

  # 环境
  env: ${APOLLO_ENV:dev}

  # 本地缓存路径(Apollo 会将配置缓存到本地文件)
  cache-dir: /tmp/apollo-config

  # 启动失败时快速失败(生产建议 false)
  bootstrap:
    eagerLoad:
      enabled: false

  # 配置变化监听
  config-change:
    listener:
      enabled: true

3.2 配置获取方式

// 方式 1:@ApolloConfig 注入(推荐)
// 自动从 application 命名空间获取
@ApolloConfig
private Config applicationConfig;

public void useConfig() {
    String endpoint = applicationConfig.getProperty("clearing.endpoint", "");
    int timeout = applicationConfig.getIntProperty("clearing.timeout", 5000);
    log.info("clearing endpoint: {}", endpoint);
}

// 方式 2:@ApolloConfigChangeListener(监听配置变化)
// 配置在 Apollo 控制台修改后,无需重启应用,立即生效
@Component
@Slf4j
public class ApolloConfigRefresher {

    private final Config applicationConfig;

    public ApolloConfigRefresher(@ApolloConfig Config applicationConfig) {
        this.applicationConfig = applicationConfig;

        // 监听 application 命名空间的变化
        applicationConfig.addChangeListener(changeEvent -> {
            for (String key : changeEvent.changedKeys()) {
                ConfigChange change = changeEvent.getChange(key);
                log.info("Apollo 配置变更: key={}, oldValue={}, newValue={}",
                    key, change.getOldValue(), change.getNewValue());

                // 刷新内存中的配置值
                if ("payment.clearing.endpoint".equals(key)) {
                    refreshClearingEndpoint(change.getNewValue());
                }

                if ("payment.limits.daily-max-amount".equals(key)) {
                    refreshDailyLimit(new BigDecimal(change.getNewValue()));
                }
            }
        });
    }
}

// 方式 3:多命名空间
@ApolloConfig("db-config")
private Config dbConfig;  // 从 db-config 命名空间读取

3.3 配置注解化

// @ApolloConfigProperties:绑定配置到 POJO
// 配置变化时自动刷新字段值

@Component
@ConfigurationProperties(prefix = "payment")
@Data
public class PaymentProperties {

    @Value("${payment.clearing.endpoint:}")
    private String clearingEndpoint;

    @Value("${payment.clearing.timeout:5000}")
    private int clearingTimeout;

    @Value("${payment.limits.daily-max-amount:0}")
    private BigDecimal dailyMaxAmount;
}

// 替代方式:使用 @RefreshScope(配合 Spring Cloud Config)
// 缺点:@RefreshScope 每次刷新会重新创建 Bean,有性能开销
@RefreshScope
@Component
@Data
public class PaymentProperties {
    @Value("${payment.clearing.endpoint:}")
    private String clearingEndpoint;
}

4. 灰度发布

Apollo 灰度发布是其最强大的功能之一:配置先对部分实例生效,观察无异常后再全量

4.1 灰度发布流程

Apollo 灰度发布流程:

步骤 1:在 Portal 创建灰度版本
  配置值: timeout = 5000
  → 点击"创建灰度版本"

步骤 2:设置灰度规则
  灰度规则(支持两种):
  ┌──────────────────────────────────────────────┐
  │ 方式 1:IP 白名单                            │
  │   灰度实例: 192.168.1.10, 192.168.1.11      │
  │   → 只有这两个 IP 收到新配置                  │
  ├──────────────────────────────────────────────┤
  │ 方式 2:百分比灰度                          │
  │   灰度比例: 10%                              │
  │   → 随机 10% 的实例收到新配置               │
  └──────────────────────────────────────────────┘

步骤 3:观察指标
  → 查看灰度实例的响应时间、错误率
  → 确认无异常

步骤 4:全量发布
  → 点击"全量发布"
  → 所有实例收到新配置

步骤 5(可选):回滚
  → 点击"回滚到 master"
  → 灰度实例恢复到旧配置

4.2 灰度 API 示例

// Java 客户端获取灰度配置
@RestController
@RequestMapping("/config")
public class ConfigController {

    @ApolloConfig
    private Config config;

    // 查询是否为灰度实例
    @GetMapping("/is-gray")
    public boolean isGrayInstance() {
        String instanceId = ConfigService.getInstance().getInstanceId();
        // 调用 Apollo Admin API 查询此实例是否在灰度列表中
        return apolloAdminService.isGrayInstance(instanceId);
    }

    // 获取当前实例的配置来源(master 或 gray)
    @GetMapping("/source")
    public String getConfigSource() {
        String configSource = config.getSource();
        return configSource != null ? configSource : "unknown";
    }
}

5. 权限管理与审计

5.1 权限模型

Apollo 权限三层模型:

全局管理员(Portal Admin)
  └── 创建、删除应用
  └── 管理系统级配置(环境、集群)

应用管理员(App Admin)
  └── 管理应用配置
  └── 添加、移除应用成员
  └── 发布配置

操作员(Operator)
  └── 只读配置
  └── 只能申请发布(需要审批)

发布审批流:
  Operator 提交发布申请

  App Admin 审批

  Team Lead 审批(可选,按组织架构)

  发布执行

5.2 权限配置

# 在 Apollo Portal 中配置:
# 1. 进入应用 → 成员管理
# 2. 分配角色:App Master / App Editor / App Viewer
# 3. 配置发布审批流(可选)

# 场景:生产环境必须经过 Team Lead 审批
# Portal → 系统设置 → 授权系统 → 开启发布审批

5.3 审计日志

-- Apollo 的 ApolloPortalDB 中记录了完整的发布历史
-- 银行合规要求:配置变更历史至少保留 5 年

SELECT
    app_id,
    env,
    cluster_name,
    namespace_name,
    key,
    old_value,
    new_value,
    operator_name,
    operation,
    operation_time
FROM publish_history
WHERE app_id = 'payment-service'
  AND env = 'PRO'
  AND operation_time > DATE_SUB(NOW(), INTERVAL 1 YEAR)
ORDER BY operation_time DESC;

-- 操作类型:
-- CREATE / UPDATE / DELETE / RELEASE / ROLLBACK

6. 与 Nacos 的选型对比

维度ApolloNacos
灰度发布✅ 完善(IP 白名单 + 百分比)❌ 不支持
权限模型✅ 完善(多级角色 + 审批流)⚠️ 基础(只有管理员)
审计日志✅ 完整(所有变更记录)⚠️ 基础(只记录版本)
多语言 SDK✅ Java/.NET/Go/Python/Node⚠️ 主要 Java
配置加密✅ 原生支持✅ 原生支持
学习曲线⚠️ 较陡(5 个组件)✅ 平缓(2 个组件)
资源占用⚠️ 较高(5+ 服务)✅ 较低
银行适用✅ 大型银行多团队✅ 中小型服务
选型口诀:

Apollo:多团队 + 强合规 + 灰度发布 大型银行生产系统
Nacos:轻量 + 快速启动 + Spring Cloud Alibaba 集成 互联网风格团队

7. 多环境配置策略

7.1 应用级 + 共享命名空间

# 命名空间设计(银行标准)

# Namespace: application(payment-service 私有)
# 权限:只有支付团队可见
payment:
  clearing:
    endpoint: https://clearing-sandbox.hsbc.com/api
    timeout: 5000

# Namespace: db-connection(多服务共享)
# 权限:所有开发团队可见,DBA 管理
database:
  payment:
    host: payment-db-dev.bank.internal
    port: 3306
    max-pool: 20

# Namespace: feature-flags(全局开关)
# 权限:产品 + 开发共享
feature:
  batch-payment-enabled: false
  crypto-remittance-enabled: false

7.2 集群隔离

# 场景:香港和深圳两个机房,数据库地址不同
# Cluster: hk-datacenter
database:
  payment:
    host: payment-db-hk.bank.internal

# Cluster: sz-datacenter
database:
  payment:
    host: payment-db-sz.bank.internal

8. 生产避坑指南

# 避坑 1:客户端本地缓存过大
# Apollo 将所有命名空间的配置缓存到本地文件
# 100+ 命名空间 → 缓存文件数百 MB
# ✅ 合理拆分命名空间,只加载必要的

# 避坑 2:配置未加密导致泄漏
# ❌ 敏感配置(数据库密码)明文存储在 Apollo
# ✅ Apollo 支持加密配置:
#    ① Portal 开启加密功能(配置加密密钥)
#    ② 配置值用 {cipher} 前缀加密存储
#    ③ 客户端解密后使用

# 避坑 3:灰度规则过于宽松
# ❌ 灰度 100% 流量 = 全量发布,没有灰度意义
# ✅ 灰度流程:1% → 5% → 20% → 50% → 100%,每步观察 10 分钟

# 避坑 4:Config Service 单点
# ❌ 单节点 Config Service → 宕机后客户端无法获取配置
# ✅ 生产至少 2 节点 + LB,Meta Server 高可用

# 避坑 5:频繁拉取导致网络开销
# ✅ Apollo 用长轮询(5 秒间隔)+ 推送模式
# ✅ 配置变化时 Config Service 主动推送到客户端

相关阅读:Nacos 服务注册与配置中心 · 服务治理:限流熔断与降级 · Spring Security 与 OAuth2 银行级安全实战