总体设计

基础模型

下图是 Apollo 配置中心的基础模型:

basic-architecture

  1. 用户在配置中心对配置进行修改并发布。
  2. 配置中心通知 Apollo 客户端有配置更新。
  3. Apollo 客户端从配置中心拉取最新的配置、更新本地配置并通知到应用。

架构模块

下图是 Apollo 架构模块的概览:

overall-architecture

各模块职责

上图简要描述了 Apollo 总体设计,我们可以从下往上看:

  • Config Service 提供配置的读取、推送等功能,服务对象是 Apollo 客户端。
  • Admin Service 提供配置的修改、发布等功能,服务对象是 Apollo Protal(管理界面)。
  • Config ServiceAdmin Service 都是多实例、无状态部署,所以需要将自己注册到 Eureka 注册中心中并保持心跳。
  • Eureka 之上我们架了一层 Meta Server 用于封装 Eureka 的服务发现接口
  • Client 通过域名访问 Meta Server 获取 Config Service 服务实例列表(IP+Port),之后直接通过 IP+Port 访问服务,同时在 Client 侧会做 load balance、错误重试。
  • Protal 通过域名访问 Meta Server 获取 Admin Service 服务实例列表(IP+Port),之后直接通过 IP+Port 访问服务,同时在 Protal 侧会做 load balance、错误重试。
  • 为了简化部署,我们实际上会把 Config ServiceEurekaMeta Server 这三个逻辑角色部署在同一个 JVM 进程中。

Why Eureka

为什么选用 Eureka

  • Eureka 提供了完整的服务注册与发现的实现
  • 无缝集成 Spring Cloud
  • 减少外部依赖

Why Meta Server

为什么在 Eureka 之上又架了一层 Meta Server

Eureka(包括 Ribbon 软负载均衡)是 Java 应用,无法天然支持多语言客户端,如果单独为多语言开发对应客户端,工作量较大。于是 Apollo 引入 Meta Server 角色,它是 Eureka 的一个 Proxy 代理,将 Eureka 的服务发现能力以 HTTP 接口的形式对外暴露,方便客户端通过简单的 HTTPClient 调用即可获得服务实例地址列表,从而进行负载均衡调用。

核心概念

  • application:应用 appApollo 对配置的管理以应用为单位,一个应用就是一个项目,对应一个唯一的 appIdApollo 客户端在运行时需要知道当前应用的 appId,从而读取配置。
  • environment:环境 env。配置对应的环境,Apollo 客户端在运行时需要知道当前应用处于哪个环境,从而读取应用的配置。
  • cluster:集群。一个应用下不同实例的分组,比如常见的按照机房分,把杭州机房的应用实例分为一个集群;把北京机房的应用实例分为另一个集群。
  • namespace:命名空间。一个应用下不同类型配置项的分组。比如可以把和 Spring 相关的配置项分为一个命名空间,把和 HTTPClient 相关的配置项分为另一个命名空间。

一个配置项隶属于某个应用。应用会区分环境,例如开发环境、生产环境等,环境不同配置项可能不同。而环境下又会因为部署的集群不同导致配置项不同,例如生产环境下部署的杭州机房集群和北京机房集群配置项可能不同。而集群下的配置项又会通过 namespace 命名空间来进行管理。

对于命名空间来说,可能某些配置项是所有应用公用的,例如数据库驱动类名 spring.datasource.driver-class-name,几乎所有 Java 应用都会配置成 com.mysql.cj.jdbc.Driver。这时我们可以去创建一个公共的命名空间,然后让具体的集群下的 namespace 去继承公共命名空间,这样就可以得到公共的配置。当然,集群下的命名空间也可以对公共命名空间中的配置项进行自定义重写覆盖。

以上核心概念的关系如下图所示:

core_concept_relation

可以看到,应用下面是环境,环境下面是集群,集群下面才是配置项,而配置项又按照 namespace 命名空间进行分类管理。