Skip to content

Apollo:一次配置发布如何抵达应用

Apollo 是一套面向微服务的分布式配置管理系统。服务端由 Portal、Admin Service、Config Service 三个主要角色组成:Portal 面向配置管理者并编排跨环境操作,Admin Service 负责写入配置、生成发布快照和回滚,Config Service 面向客户端提供配置读取、变更通知与 Meta Server 服务发现。配置数据和发布通知落在数据库中,Java、.NET 等客户端则从 Config Service 获取结果。

理解 Apollo 的关键,是把“编辑配置”和“应用看到配置”分开。编辑中的 Item 不会直接暴露给客户端;发布动作会把一组配置固化成不可变的 Release 快照,再把一条轻量的 ReleaseMessage 写进数据库。Config Service 扫描消息、刷新灰度规则和缓存、唤醒长轮询,客户端收到“有变化”的信号后再拉取新配置。数据库因而既保存业务事实,也承担了一条简单的跨进程通知总线。

源码还保留了几层有意设计的退路:指定集群取不到配置时回退到机房和默认集群;灰度规则不命中时回退正式发布;增量同步计算失败时回退全量;Portal 访问 Admin Service 时只对可安全重试的失败切换实例。分析范围覆盖服务端模块、三角色启动、发布、通知、读取、灰度、缓存、增量与回滚。Java Client 的函数级实现不在本仓库中,当前服务端只通过外部 apollo-java 依赖与客户端协议衔接。

GitHub 仓库信息

信息内容
项目标题Apollo
项目描述Apollo 是一套可靠的配置管理系统,可集中管理不同应用、不同集群的配置,适用于微服务配置管理场景。
GitHub 仓库apolloconfig/apollo
官网地址www.apolloconfig.com
主要开发语言Java 73.28%、JavaScript 12.23%、HTML 11.54%
开源许可证Apache-2.0
最近代码更新2026-08-31(GitHub pushed_at,核对日期:2026-09-02)

仓库结构与模块职责

Apollo 是 Maven 多模块仓库。下面的目录树保留运行时主干,并把构建辅助、文档和测试收在末尾;这张目录树只作为阅读索引,不代表逐文件覆盖。

text
apollo/
├── apollo-common/              服务端共享 DTO、实体、异常和配置抽象
├── apollo-biz/                 配置领域模型、Release、灰度、消息与持久化
├── apollo-configservice/       配置查询、Meta Server、长轮询与服务端缓存
├── apollo-adminservice/        配置写入、发布、回滚和管理 API
├── apollo-portal/              管理界面、OpenAPI、权限与跨环境编排
├── apollo-assembly/            三个服务的一体化启动入口
├── apollo-audit/               审计注解、API、实现和 Spring Boot Starter
├── apollo-buildtools/          代码风格与构建支持
├── apollo-build-sql-converter/ 构建期 SQL 转换辅助
├── scripts/sql/                MySQL 建库与初始化脚本
├── docs/                       设计、开发、部署和客户端文档
└── e2e/                        服务发现与 Portal 端到端测试

pom.xml 给出了最清楚的仓库边界:服务端当前版本为 3.0.0-SNAPSHOT,基线是 Java 17、Spring Boot 4.1.1 和 Spring Cloud 2025.1.3;apollo-coreapollo-openapi 等客户端侧能力来自独立的 apollo-java:2.5.0 依赖。

模块或核心文件负责什么与上下游的关系
apollo-common共享 ReleaseDTO、NamespaceDTO、异常、实体和可刷新配置抽象为 Portal、Admin Service、Config Service 提供共同语言
apollo-biz实现发布快照、灰度分支、回滚、数据库消息、Repository被 Admin Service 写入,也被 Config Service 读取和监听
apollo-portal提供 Web UI、OpenAPI、权限校验和多环境管理通过 Meta Server 找到 Admin Service,再发起管理请求
apollo-adminservice接收管理请求并在事务中修改 ApolloConfigDB发布完成后写 ReleaseMessage,驱动 Config Service 更新
apollo-configservice提供 /configs、/configfiles、/notifications/v2读取 Release,向外部客户端返回配置或变更信号
ApolloApplication在一个 JVM 中依次创建公共、Config、Admin、Portal 上下文适合本地开发和一体化体验,不替代生产角色拆分
ReleaseService把编辑态 Item 组装为 Release,处理锁、分支和历史上接 Admin Controller,下接 Release Repository
ReleaseMessageScanner周期扫描新的 ReleaseMessage 并广播给监听器串起缓存失效、灰度刷新和长轮询通知

apollo-portal 同时包含后端 Java 与 AngularJS 静态资源,因此语言统计中的 JavaScript 和 HTML 并非另一套服务端。apollo-audit 是横切能力;构建工具和 E2E 测试对工程质量重要,但不进入一次配置发布的运行链。

核心能力如何落到源码

用发布快照隔离编辑态

Portal 中保存 Item 只是编辑配置,客户端读取的是最新有效 Release。Admin Service 的 ReleaseController.publish 先找到 Namespace,再调用领域服务生成快照;ReleaseService 会检查锁、读取当前 Item、区分主干或灰度分支,并保存新的 Release。

这个设计让“保存”和“生效”拥有不同边界。收益是审核、比较、回滚和灰度可以围绕稳定快照展开;代价是数据模型与操作流程更复杂,排障时也必须先确认问题发生在编辑态、发布态还是客户端已加载状态。

用数据库消息连接写路径与读路径

发布事务生成 Release 后,Admin Service 不直接调用每个 Config Service,而是写入内容形如 appId+cluster+namespace 的 ReleaseMessage。DatabaseMessageSender 把消息保存到表中,并异步清理同一 Namespace 的旧消息。

Config Service 默认每秒扫描新消息。扫描器每批读取 500 条;若自增 ID 中出现空洞,会暂存缺失 ID 并在后续轮次补查,而不是假设消息永久不存在。数据库消息方案比引入专用消息中间件更容易部署,也使 Release 与通知共享数据库事务边界;对应的成本是通知延迟依赖轮询间隔,ConfigDB 还承担额外扫描压力。

长轮询只通知“有变化”

Config Service 的 NotificationControllerV2 使用 DeferredResult 挂起请求。控制器先注册监听关系,再查询最新 ReleaseMessage,专门封住“检查完没有变化、注册前恰好发布”这条丢通知窗口。异步请求建立后还会主动关闭 EntityManager,避免 60 秒长轮询占住数据库连接。

消息到达时,服务端只返回发生变化的 Namespace 及通知 ID,不把完整配置塞进通知响应。客户端随后再访问配置接口。服务端默认按 100 个连接一批、批间隔 100ms 唤醒大量请求,避免同一个 Namespace 的大规模更新在一个瞬间集中冲击执行线程。

分层选择配置并支持灰度

读取配置时,AbstractConfigService 按指定 Cluster、Data Center、default 的顺序查找。每一层又先根据客户端 appId、IP 或 label 查找灰度 Release,规则不匹配或灰度发布无效时才选择该层最新的正式 Release。

这段顺序同时解释了 Apollo 的环境隔离和灰度能力:环境通常对应独立 ConfigDB 与服务集群,Cluster/Data Center 在环境内部提供更细的覆盖,Namespace 划分配置域,灰度分支只对匹配客户端改变结果。层级带来了控制力,也带来了“同一个 key 到底来自哪一层”的诊断成本。

缓存、304 与增量同步各管一段成本

ConfigController 会先读取应用自己的配置,再按需合并公共 Namespace。若合并后的 release key 与客户端一致,接口返回 HTTP 304;若开启增量同步,服务端尝试对比客户端历史 Release 与最新 Release,只返回变更项,计算异常时自动回退全量结果。

config-service.cache.enabled 决定 Config Service 使用数据库直读还是本地缓存。ConfigServiceWithCache 收到 ReleaseMessage 后失效并预热缓存;客户端携带的通知消息比缓存记录更新时,读取路径也会主动失效重载。缓存减少数据库读取,却增加内存占用和一致性分支,因此源码默认关闭。

源码环境与本地运行

这次分析只读取固定提交,没有执行 Maven、数据库脚本、容器或服务。下面是官方开发文档与构建文件共同确认的本地路径,命令不是“亲测成功”记录。

准备条件

  • JDK 17 或更高版本;根 POM 的 java.version 同样固定为 17。
  • Maven。仓库带有 Maven Wrapper,但正式运行前仍应核对本机代理、镜像和可写缓存目录。
  • MySQL 5.6.5 或更高版本;只做本地开发时也可使用 H2 内存或文件数据库。
  • 可用端口:Portal 8070、Config Service/Meta Server 8080、Admin Service 8090。
  • 首次编译 Portal 时需要生成 OpenAPI DTO。

在一个新目录中获取分析使用的固定提交:

bash
git clone https://github.com/apolloconfig/apollo.git
cd apollo
git checkout 5d438a23f5b6604245b5f7a6b09a31781a3fdc34

git rev-parse HEAD 应输出同一完整提交。若不是,后续类名、依赖和行为可能已变化。

Portal 首次导入 IDE 时,先在仓库根目录触发 OpenAPI 代码生成:

bash
mvn clean compile -pl apollo-portal -am

成功信号是 Maven 构建完成,且生成的 com.ctrip.framework.apollo.openapi.model.OpenXxxDTO 能被 IDE 识别。若这些类型仍报缺失,先检查命令是否在仓库根目录执行,再看 OpenAPI Generator 的 Maven 日志。

一体化启动

官方开发指南推荐在 IDE 中运行:

text
com.ctrip.framework.apollo.assembly.ApolloApplication

使用仓库内置 H2 路径时,开发文档给出的 VM 参数是:

text
-Dapollo_profile=github,auth

若改用 MySQL,需要先导入 scripts/sql/profiles/mysql-default/ 下的两个数据库脚本,并提供 spring.config-datasource.*spring.portal-datasource.*。不要把示例用户名、密码或数据库地址直接用于共享环境。

希望从命令行构建一体化模块时,可以按 Maven 依赖关系执行:

bash
mvn clean package -pl apollo-assembly -am -DskipTests=true

构建完成后从 apollo-assembly/target/ 选择实际生成的可执行 JAR;官方 Quick Start 将该文件命名为 apollo-all-in-one.jar 后运行:

bash
java -jar apollo-all-in-one.jar

不要在构建成功前假定 JAR 文件名。当前仓库文档同时包含 IDE 开发路径、Quick Start 包路径和生产分角色部署,三者的 profile 与产物组织并不完全相同。

判断是否真的启动

健康检查比“进程还在”更可靠:

text
http://localhost:8080/health
http://localhost:8090/health
http://localhost:8070

Config Service 和 Admin Service 的健康响应中 status.code 应为 UP,Portal 页面应能打开。启用 auth profile 时,开发文档给出的默认登录是 apollo/admin,只适合本地体验,不能当作生产配置。

要完成一次有意义的验证,还应在 Portal 新建应用和 Namespace、发布一个如 timeout=100 的配置,再使用独立的 apollo-demo-java 连接 http://localhost:8080。Demo 输入 timeout 后显示 Loading key : timeout with value: 100,才说明管理、发布、通知和读取路径基本连通。客户端 Demo 及其内部实现不属于当前固定仓库。

整体架构地图

Portal 是管理面,Admin Service 是写路径,Config Service 是读路径。生产部署中,每个环境通常有自己的 Config Service、Admin Service 与 ApolloConfigDB;一个 Portal 可以通过不同环境的 Meta Server 地址管理多套环境。客户端需要访问 Meta Server 和 Config Service,不应开放到 Admin Service 的直接网络路径。

想找的功能建议从哪里开始
一体化启动顺序apollo-assembly/.../ApolloApplication.java
单角色启动与端口三个 *Application.java 和各模块 properties
Portal 发布与权限apollo-portal/.../openapi/v1/controller/ReleaseController.java
Portal 到 Admin 的容错AdminServiceAPI.javaRetryableRestTemplate.java
Release 生成、灰度与回滚apollo-biz/.../service/ReleaseService.java
数据库消息写入与扫描DatabaseMessageSender.javaReleaseMessageScanner.java
长轮询注册与唤醒NotificationControllerV2.java
配置层级与灰度选择AbstractConfigService.javaGrayReleaseRulesHolder.java
服务端缓存与增量返回ConfigServiceWithCache.javaConfigController.java
权限与审计Portal security 包、apollo-audit
数据库与生产配置scripts/sql/docs/zh/deployment/

入口与启动链路

三种角色入口

部署形态入口主要职责
一体化开发ApolloApplication在一个 JVM 内启动三套 Web 子上下文
Config ServiceConfigServiceApplicationMeta Server、配置读取、通知、缓存和扫描
Admin ServiceAdminServiceApplication管理 API、发布、回滚和数据写入
PortalPortalApplicationWeb/OpenAPI、权限、环境路由和管理编排

一体化入口先创建不提供 Web 服务的 commonContext,随后以 commonContext 为父上下文,按 Config Service、Admin Service、Portal 的顺序创建三个子上下文。子上下文统一启用 assembly profile,并额外加载 RefreshScope。一体化模式共享父容器和进程,三个角色的 Controller、配置和端口仍保持各自边界。

Config Service 的关键初始化发生在 ConfigServiceAutoConfiguration:根据 config-service.cache.enabled 选择数据库直读或缓存实现,创建灰度规则持有器,并把 ReleaseMessage 监听器按“消息缓存、灰度规则、服务端缓存、文件缓存、客户端通知”的顺序注册到扫描器。这个顺序保证客户端被唤醒前,服务端尽量已经看见新规则和新 Release。

停止路径也有资源边界。数据库消息发送器会设置停止标记,后台线程使用 daemon thread;长轮询请求完成或超时后从监听映射中注销。源码没有在一体化入口手写关闭顺序,Spring ApplicationContext 负责执行 Bean 的销毁回调。

核心链路矩阵

链路入口关键交接最终结果或副作用
服务启动ApolloApplication 或三个角色 mainSpring 父子上下文、profile、自动配置三个端口与后台扫描任务就绪
正常发布OpenAPI v1 Release ControllerPortal → Admin → biz ReleaseService新 Release 与 ReleaseMessage 入库
变更通知ReleaseMessageScanner消息缓存 → 灰度 → 配置缓存 → Notification挂起客户端获得 Namespace 变更
配置读取/configs/{appId}/{cluster}/层级选择 → 灰度 → 公共配置合并304、增量或全量配置
灰度发布灰度 Release 入口分支快照 → 规则缓存 → 客户端匹配只有命中 appId/IP/label 的客户端得到灰度值
回滚Portal/Admin rollback标记 Release abandoned → 历史记录 → 消息读路径回到目标有效 Release
Portal 容错RetryableRestTemplateMeta Server → Admin Service 实例列表安全失败时切换实例,否则保留原错误

一次正常发布

正常发布链选取实现 OpenAPI v1 契约的 ReleaseController 作为入口。OpenAPI 控制器先做发布权限、参数和紧急发布检查,再把请求交给 Portal ReleaseService。仓库中的其他发布 Controller 不并入这条已核对链路。

Portal 的 AdminServiceAPI.ReleaseAPI 把调用转成表单 POST。Admin Controller 与消息发送处于同一个事务方法中:Release 生成成功后才发送 ReleaseMessage,异常会沿 HTTP 调用返回 Portal。消息内容只携带定位键,完整配置仍由 Release 表承载。

从消息扫描到客户端被唤醒

这里有一个容易忽略的认知转折:Apollo 的长轮询通知并不要求客户端恰好在线。ReleaseMessage 是数据库中的单调 ID 记录;新请求注册后会立即比较自己的通知 ID 与服务器最新 ID。因此,“发布时没有挂起请求”不会让变更永久丢失。

客户端读取配置

客户端收到通知后,会向 Config Service 请求完整配置或增量变化。服务端读取顺序如下:

  1. 规范化 Namespace,补充请求 IP,并解析客户端携带的消息版本。
  2. 读取当前应用配置;若 Namespace 不属于当前应用,再加载公共 Namespace。
  3. 每份配置内部执行“指定 Cluster → Data Center → default”,每层先灰度后正式 Release。
  4. 合并应用与公共配置,计算组合 release key。
  5. release key 未变化时返回 304。
  6. 开启增量同步且能找到历史 Release 时返回变更项,否则返回全量。

客户端 SDK 的“本地缓存、定时拉取、监听器回调”属于独立 apollo-java 仓库。当前服务端源码只能确认 HTTP 契约和通知行为,不能据此宣称已经走读客户端线程模型。

灰度、缓存和文件接口

灰度规则持有器维护正向规则与按 appId、Namespace、IP/label 建立的反向索引,并通过 ReleaseMessage 增量刷新;定时全量扫描则处理消息遗漏或规则状态变化。Config File 接口遇到可能命中灰度的请求时不会直接复用普通文件缓存,避免把某个客户端的灰度值泄漏给其他客户端。

启用 Config Service 缓存后,ReleaseMessage 既是通知,又是缓存版本信号。读取请求携带的 message ID 还能发现本机缓存落后并触发回源。“消息监听 + 请求版本比较”提升了最终一致性韧性,但不构成强一致事务:消息扫描、缓存刷新和客户端拉取之间仍存在短暂时间窗。

分支、失败与恢复

Portal 到 Admin Service 的重试边界

RetryableRestTemplate 从服务发现结果取得 Admin Service 列表,依次尝试实例,并可按环境附加 access token。重试规则区分了两类失败:

  • GET 遇到连接超时、连接失败或读超时,可以切换实例重试。
  • POST、PUT、DELETE 只在尚未建立连接的失败上重试;读超时不重试,因为远端可能已经完成写入,重复提交会制造二次副作用。

所有实例不可用时,Portal 抛出包含 Meta Server 和实例列表的 ServiceException。业务异常不进入重试。这个实现没有引入通用重试框架,却把幂等性边界写得很清楚。

读取路径的降级顺序

配置读取没有“任意回退到旧值”的服务端逻辑。可确认的服务端分支是:

  • 指定 Cluster 无 Release:继续 Data Center,再继续 default。
  • 灰度规则不命中或 Release 无效:使用同层正式 Release。
  • 应用私有 Namespace 不存在:若同名 Namespace 是公共配置,再加载公共配置;全部为空则返回 404。
  • release key 相同:返回 304,而非重复传输。
  • 增量计算异常或历史 Release 不可用:回退全量同步。
  • 缓存关闭:使用数据库查询实现;缓存开启:按消息失效与回源。

客户端断网时是否读取本地文件、监听器如何触发,需到对应 SDK 仓库核对,不能从 Config Service 的 404 或长轮询超时推导。

回滚不是复制一份旧配置

Admin Service 的 rollback 会验证当前 Release 可用且至少存在两个有效版本,然后把当前版本标记为 abandoned,记录 ReleaseHistory,并处理可能存在的子 Namespace。rollbackTo 则把目标版本之后、当前版本之前的多个 Release 标记为 abandoned。Controller 最后仍发送 ReleaseMessage,因此回滚与正常发布共用同一条通知链。

这意味着客户端选择的是“最新有效 Release”,而不是 Admin Service 把旧 JSON 复制成新 Release。回滚历史清晰,但清理或迁移 Release 数据时必须尊重 abandoned 与历史关系。

通知链的可观察失败点

位置可观察现象排查入口
Portal 找不到 Admin Service“No available admin server” 或全部实例无响应Meta Server 地址、服务发现记录、Admin /health
发布未生成消息Portal 请求失败,Release/ReleaseMessage 不完整Admin 日志、事务异常、ApolloConfigDB
Scanner 延迟或失败Release 已存在,长轮询暂未返回Apollo.ReleaseMessageScanner 日志、扫描间隔、DB 负载
灰度未命中普通值正常,目标客户端仍取正式值appId、IP、label、规则状态与灰度 Release
缓存落后客户端通知 ID 高于缓存记录ConfigCache.Invalidate、回源日志、ReleaseMessage
大批客户端更新慢同 Namespace 客户端分批收到通知notification batch 与 interval 配置

设计判断

值得学习的地方

用 Release 建立清晰的生效边界。 编辑、发布、回滚和客户端读取围绕不同状态组织,避免“保存一条 Item 就立即影响线上”。这套思路适合任何需要审核、追溯和灰度的控制面。

用通知 ID 封住长轮询竞态。 先注册后检查,以及客户端 ID 与服务端最新 ID 比较,使通知不依赖某次瞬时事件是否被监听到。这里的可靠性来自持久化状态与比较协议,不是把长连接本身当成可靠消息。

重试策略尊重写操作的不确定性。 GET 的读超时可以切换实例,写请求的读超时保持失败并交给上层判断,避免“为了高可用”制造重复发布。

缓存是可替换实现,不改变查询语义。 ConfigService 抽象下有数据库与缓存两种实现,集群回退和灰度选择在共同父类完成。缓存优化不会复制一套业务选择规则。

需要承担的代价

数据库职责偏重。 ApolloConfigDB 同时承载配置事实、发布历史、服务端动态配置、实例审计和消息扫描。部署简单,但高发布频率或大规模实例下需要认真规划索引、连接池、扫描间隔、备份与容量。

多层覆盖增加解释成本。 环境、Cluster、Data Center、Namespace、公共配置和灰度分支共同决定结果。平台能表达复杂组织结构,使用者也更容易遇到“Portal 里看到的值与某台机器不同”。

Portal 与 Admin Service 是同步 HTTP 编排。 服务发现和有限重试提升可用性,但发布仍受目标环境 Admin Service 健康与网络影响。跨很多环境的集中 Portal 需要清楚地呈现部分失败,不能把一次 UI 操作当成全局事务。

服务端与客户端分仓。 有利于独立发版,却使端到端源码分析必须同时固定服务端和 SDK 版本。当前服务端 3.0.0-SNAPSHOT 依赖 apollo-java:2.5.0,版本兼容判断不能只看一个仓库。

若要扩展发布流程,从 Portal OpenAPI Controller、Portal ReleaseService 和 AdminServiceAPI 开始;要排查客户端未更新,从 Release、ReleaseMessage、Scanner、NotificationControllerV2、ConfigController 依次向外检查;要改变灰度匹配,重点阅读 GrayReleaseRulesHolder 与 AbstractConfigService,同时补齐 Config File 缓存隔离测试。

应用场景与同类方案

Apollo 适合多环境、多集群、需要配置发布审计、灰度和回滚的 Java 微服务体系,尤其适合由平台团队统一管理、应用团队通过 Portal 或 OpenAPI 协作的组织。配置量很小、只依赖部署时静态文件的系统,或无法维护数据库和多角色服务的团队,采用 Apollo 的收益可能抵不过运维成本。

下面是架构层面的统一维度比较,不是性能基准:

方案核心定位数据与通知形态管理与治理主要取舍
Apollo配置发布平台Release 快照、数据库消息扫描、长轮询Portal、环境/集群/Namespace、灰度、审计与回滚管理能力完整,服务和数据库模型更重
Nacos服务发现与配置管理平台服务注册与配置通知由 Nacos 集群统一承担控制台、Namespace/Group/Data ID能力面更宽;若只要配置发布,需接受更综合的平台边界
Spring Cloud ConfigGit 等后端驱动的配置服务客户端拉取;动态广播常与 Bus 等组件组合贴近 Spring/Git 工作流组件简单直观;灰度、Portal 和发布治理通常要自行补充
Consul KV服务发现、健康检查与 KVConsul 一致性存储、阻塞查询/watch通用 KV 与服务治理基础设施统一;配置发布模型和业务级权限审计较弱

如果团队最看重配置发布流程、可视化管理和灰度,Apollo 的边界更贴近需求;如果同时要服务发现与统一云原生控制面,可以优先比较 Nacos;若 Git 审核已经是唯一变更入口,Spring Cloud Config 更直接;若基础设施已经全面采用 Consul,KV 与 blocking query 可能降低新增系统成本。

构建、部署与调试问题

本节来自固定提交中的开发、部署和 FAQ 文档以及静态源码,没有在本机启动服务。

Portal 的 OpenAPI DTO 找不到

现象: IDE 报 OpenXxxDTO 或 ReleaseManagementApi 缺失。

原因: apollo-portal 在 Maven 编译阶段根据 YAML 生成代码,首次拉取后目标目录尚不存在。

处理:

bash
mvn clean compile -pl apollo-portal -am

验证: Maven 成功结束,生成包能被 IDE 索引;若失败,查看 OpenAPI Generator 阶段而不是手写缺失 DTO。

8080、8090 或 8070 被占用

现象: Config Service、Admin Service 或 Portal 启动时报 bind/address already in use;官方 FAQ 特别提到某些本地代理可能占用 8090。

处理: 检查监听进程,停止冲突服务或调整对应 server.port。修改 Config Service 端口后,还要同步 Portal 与客户端的 Meta Server 地址;使用旧 Eureka 模式时还需更新 eureka.service.url。

验证: 三个健康入口可访问,Portal 系统信息中的 Meta Server 与 Admin Service 地址正确。

Portal 打得开,但发布时报找不到 Admin Service

现象: Portal 显示 No available admin server 或所有 Admin Service 无响应。

原因: Portal 先访问当前环境的 Meta Server,再取得 Admin Service 实例;环境地址、注册信息或网络任一环节错误都会中断。

处理: 核对 apollo.portal.meta.servers 或环境对应的 meta 地址,检查 Config Service 与 Admin Service 健康状态,并确认 Portal 到两个服务端口的网络。客户端只需访问 8080,不应因此开放 8090。

验证: Portal 的系统信息页面能看到目标环境的 Meta Server 和 Admin Service,发布请求返回 Release 信息。

数据库启动失败或表不存在

现象: DataSource 初始化失败、找不到 ServerConfig/Release 等表,或 PortalDB 与 ConfigDB 混用。

处理: MySQL 路径分别导入 apolloportaldb.sqlapolloconfigdb.sql;确认 spring.portal-datasource.* 指向 ApolloPortalDB,spring.config-datasource.* 指向 ApolloConfigDB。环境级 Config Service/Admin Service 只应访问本环境的 ConfigDB。

验证: 两个数据源健康,Portal 能读取环境信息,Config/Admin 的 /health 返回 UP。

3.0 服务发现模式与旧部署不一致

3.0 起,官方 Release 包、Docker 镜像以及默认构建脚本为 Config Service 和 Admin Service 启用 github,database-discovery。从旧 Eureka 部署升级而仍需保持原行为时,要显式使用 SPRING_PROFILES_ACTIVE=github,或在 config/application.properties 中配置 spring.profiles.active=github

验证时不要只看进程:应确认实际 profile、服务发现记录、Portal 能找到 Admin Service、客户端能通过 Meta Server 找到 Config Service。切换发现方式属于部署架构变更,应先在非生产环境验证。

发布成功但客户端没有变化

沿数据事实逐层检查:

  1. Release 是否已生成且未 abandoned。
  2. 对应 appId+cluster+namespace 的 ReleaseMessage 是否存在。
  3. Config Service Scanner 是否扫描到该消息。
  4. 目标客户端的 appId、Cluster、Data Center、IP、label 是否落入预期分支。
  5. /configs 返回的是 304、增量还是全量,release key 是否变化。
  6. 最后再进入对应 SDK 仓库检查本地缓存和监听器。

这个顺序能把服务端发布问题与客户端加载问题分开,避免一开始就重启全部组件。

总结与阅读路径

Apollo 的主线可以压缩成四个动作:Portal 编排管理请求,Admin Service 把编辑态配置固化成 Release,ReleaseMessage 驱动 Config Service 刷新并通知,客户端收到变化后重新读取。灰度、缓存、增量与回滚都围绕 Release 选择和同一条消息链扩展。

继续读源码时,可以按目标选择入口:

  • 要修改发布或审批边界:从 OpenAPI v1 Release Controller 读到 Portal ReleaseService、AdminServiceAPI 和 Admin Controller。
  • 要排查配置未生效:按 Release → ReleaseMessage → Scanner → NotificationControllerV2 → ConfigController 顺序核对。
  • 要理解灰度结果:从 GrayReleaseRulesHolder 的索引和规则刷新读到 AbstractConfigService 的层级选择。
  • 要评估规模成本:重点看 ReleaseMessage 扫描、通知批次、Config Service 缓存、实例审计和数据库配置。
  • 要继续客户端链路:固定匹配版本后转到 apolloconfig/apollo-java 或对应语言 SDK,不把两个仓库的版本混写。

参考资料

文章结论绑定 source commit;动态信息以核对日期为准。