看到 InfoQ 的一篇文章:GitHub 9K Star!Apollo作者手把手教你微服务配置中心之道
关于为什么需要配置中心,请参见:Spring Cloud 学习笔记 - No.3 分布式配置 Config
携程 Apollo(阿波罗)Github 主页:https://github.com/ctripcorp/apollo
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
Apollo 的基础模型
- 用户在配置中心对配置进行修改并发布
- 配置中心通知 Apollo 客户端有配置更新
- Apollo 客户端从配置中心拉取最新的配置、更新本地配置并通知到应用
服务端高可用
- 首先最下面是一个 DB,我们的配置是放在 DB 里的,然后在 DB 之上有两个服务:Config Service 和 Admin Service;
- Config Service 提供配置的读取、推送等功能,服务对象是 Apollo 客户端;
- Admin Service 提供配置的修改、发布等功能,服务对象是 Apollo Portal(管理界面);
- Config Service 和 Admin Service 都是多实例、无状态部署,所以需要将自己注册到 Eureka 中并保持心跳;
- 在 Eureka 之上我们架了一层 Meta Server 用于封装 Eureka 的服务发现接口,主要是为了让客户端和 Eureka 解耦;
- Client 通过域名访问 Meta Server 获取 Config Service 服务列表(IP+Port),而后直接通过 IP+Port 访问服务,同时在 Client 侧会做 load balance、错误重试;
- Portal 通过域名访问 Meta Server 获取 Admin Service 服务列表(IP+Port),而后直接通过 IP+Port 访问服务,同时在 Portal 侧会做 load balance、错误重试;
- 为了简化部署,我们实际上会把 Config Service、Eureka 和 Meta Server 三个逻辑角色部署在同一个 JVM 进程中;
客户端高可用
- 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过 Http Long Polling 实现);
- 客户端还会定时从 Apollo 配置中心服务端拉取应用的最新配置;这是一个 fallback 机制,为了防止推送机制失效导致配置不更新;
客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回 304 - Not Modified。 - 客户端从 Apollo 配置中心服务端获取到应用的最新配置后,会保存在内存中,所以我们的应用程序来获取配置的时候其实始终是从内存中获取的;
- 客户端还会把从服务端获取到的配置在本地文件系统缓存一份;
这主要是为了容灾,假设应用程序重启的时候,恰好远端服务全挂了,或者网络有故障,应用程序依然能从本地恢复配置。
通过这种推拉结合的机制,以及内存和本地文件双缓存的方式,有效地保证了客户端的可用性。
发送 ReleaseMessage 的实现方式
Admin Service 在配置发布后,需要通知所有的 Config Service 有配置发布,从而 Config Service 可以通知对应的客户端来拉取最新的配置。
从概念上来看,这是一个典型的消息使用场景,Admin Service 作为 producer 发出消息,各个 Config Service 作为 consumer 消费消息。通过一个消息组件(Message Queue)就能很好的实现 Admin Service 和 Config Service 的解耦。
在实现上,考虑到 Apollo 的实际使用场景,以及为了尽可能减少外部依赖,我们没有采用外部的消息中间件,而是通过数据库实现了一个简单的消息队列。
实现方式如下:
- Admin Service 在配置发布后会往 ReleaseMessage 表插入一条消息记录,消息内容就是配置发布的 AppId+Cluster+Namespace
- Config Service 有一个线程会每秒扫描一次 ReleaseMessage 表,看看是否有新的消息记录
- Config Service 如果发现有新的消息记录,解析得到配置发布的 AppId+Cluster+Namespace 后,通知到对应的客户端
分布式配置中心如何让微服务更『智能』?
发布开关
有些新功能依赖于其它系统的新接口,而其它系统的发布周期未必和自己的系统一致,可以加个发布开关,默认把该功能关闭,等依赖系统上线后再打开;
有些新功能有较大风险,可以加个发布开关,上线后一旦有问题可以迅速关闭。
实验开关
实验开关通常用于对比测试或功能测试,比如:A/B 测试和QA 测试。
运维开关
运维开关通常用于提升系统稳定性,比如:
- 大促前可以把一些非关键功能关闭来提升系统容量;
- 当系统出现问题时可以关闭非关键功能来保证核心功能正常工作。
限流
黑白名单
一般的做法是在 RPC 框架层添加校验逻辑,结合配置中心的动态推送能力来实现动态调整黑白名单配置。
数据库迁移
动态日志级别
动态网关路由
动态数据源
关于 Apollo 的使用
服务端基于Spring Boot和Spring Cloud开发,打包后可以直接运行,不需要额外安装Tomcat等应用容器。
Java客户端不依赖任何框架,能够运行于所有Java运行时环境,同时对Spring/Spring Boot环境也有较好的支持。
本地快速部署请参见Quick Start
演示环境(Demo):
- 106.12.25.204:8070
- 账号/密码:apollo/admin
关于 Spring 如何集成 Apollo,请参见:Java客户端使用指南#32-spring整合方式