Apollo配置中心

简介和命名空间及应用

Posted by HH on July 5, 2021

Apollo简介

Apollo是携程研发的开源配置管理中心,能够集中话管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。

Apollo支持4个维度管理key-value格式的配置:

  1. application应用
  2. environment环境
  3. cluster集群
  4. namespace命名空间

配置的基本概念

Apollo定位与配置中心,那么在这里必要先简单介绍一下什么是配置。

按照我们的理解,配置有以下几个属性:

  • 配置是独立于程序的只读变量
    • 配置首先是独立于程序的,同一程序在不同的配置下会有不同的行为。
    • 其次,配置对于程序是只读的,程序通过读取配置来改变自己的行为,但是程序不应该去改变配置。
    • 常见的配置有:DB Connection Str、Thread Pool Size、Buffer Size、Request Timeout、Feature Switch、Server Urls等。
  • 配置伴随应用的整个生命周期
    • 配置贯穿于应用的整个生命周期,应用在启动时通过读取配置来初始化,在运行时根据配置调整行为。
  • 配置可以有多种加载方式
    • 配置有很多中加载方式,常见的有程序内部hard code,配置文件,环境变量,启动参数,基于数据库等
  • 配置需要治理
    • 权限控制
      • 由于配置能改变程序的行为,不正确的配置甚至能引起灾难,所以对配置的修改必须有比较完善的权限控制
    • 不同环境、集群配置管理
      • 同一份程序在不同的环境(开发,测试,生产)、不同的集群(如不同的数据中心)经常需要有不同的配置,所以需要有完善的环境、集群配置管理
    • 框架类组件配置管理
      • 还有一些比较特殊的配置-框架类组件配置,比如CAT客户端的配置。
      • 虽然这类框架类时由其他团队开发、维护,但是运行时时在业务实际应用内的,所以本质上可以认为框架类组件也是应用的一部分。
      • 这类组件对应的配置也需要比较完善的管理方式

Namespace的类型

Namespace类型有三种:

  • 私有类型
  • 公共类型
  • 关联类型(继承类型)

私有类型

私有类型的Namespace具有private权限,例如默认的application就是私有类型。

公共类型

含义

公共类型的Namespace具有public权限。公共类型的Namespace相当于游离于应用之外的配置,且通过Namespace的名称去标识公共Namespace,所以公共的Namespace的名称必须全局危矣。

使用场景
  • 部门级别共享的配置
  • 小组级别共享的配置
  • 几个项目之间共享的配置
  • 中间件客户端的配置

关联类型

含义

关联类型又可称为继承类型,关联类型具有private权限。关联类型的Namespace继承于公共类型的Namespace,用于覆盖公共Namespace的某些配置。例如公共的Namespace有两个配置项

k1 = v1
k2 = v2

然后应用A有一个关联类型的Namespace关联了此公共Namespace,且覆盖了配置项k1,新值为v3。那么在应用A实际运行时,获取到公共Namespace的配置为:

k1 = v3
k2 = v2
使用场景

举个实际使用的场景。假设RPC框架的配置(如:timeout)有以下要求:

  • 提供一份全公司默认的配置且可动态调整
  • RPC客户端项目可以自定义某些配置项且可动态调整
  1. 如果把以上两点要求去掉“动态调整”,那么做法很简单。在rpc-client.jar包里有一个份配置文件,每次修改配置文件然后重新发一个版本的jar包即可。同理,客户端项目修改配置也是如此。
  2. 如果只支持客户端项目可动态调整配置。客户端项目可以在Apollo “application” Namespace上配置一些配置项。在初始化service的时候,从Apollo上读取配置即可。这样做的坏处就是,每个项目都要自定义一些key,不统一。
  3. 那么如何完美支持以上需求呢?答案就是结合使用Apollo的公共类型的Namespace和关联类型的Namespace。RPC团队在Apollo上维护一个叫“rpc-client”的公共Namespace,在“rpc-client” Namespace上配置默认的参数值。roc-client.jar的代码读取“rpc-client” Namespace的配置即可。如果需要调整默认的配置,只需要修改公共类型“rpc-client”Namespace的配置。如果客户端想要自定义或者动态修改某些配置项,只需要在Apollo自己项目下关联“rpc-client”,就能创建关联类型“rpc-client”的Namespace。然后在关联类型“rpc-client”的Namespace下修改配置即可。这里有一点需要指出的,那就是rpc-client.jar是应用容器里面运行的,所以rpc-client获取的“rpc-client”Namespace的配置是应用的关联类型的Namespace加上公共类型Namespace。

例子

如下图所示,有三个应用:应用A、应用B、应用C。

  • 应用A有两个私有类型的Namespace:application和NS-Private,以及一个关联类型的Namespace:NS-Public。
  • 应用B有一个私有类型的Namespace:application,以及一个公共类型的Namespace:NS-Public。
  • 应用C只有一个私有类型Namespace:application

Namespace例子

应用A获取Apollo配置
//application
Config appConfig = ConfigService.getAppConfig();
appConfig.getProperty("k1",null);//k1 = v11
appConfig.getProperty("k2",null);//k2 = v21

//NS-Private
Config privateConfig = ConfigService.getConfig("NS-Private");
privateConfig.getProperty("k1",null);//k1 = v3
privateConfig.getProperty("k3",null);//k3 = v4

//NS-Public,覆盖公共类型配置的情况,k4被覆盖
Config publicConfig = ConfigService.getConfig("NS-Public");
publicConfig.getProperty("k4",null);//k4 = v6 cover
publicConfig.getProperty("k6",null);//k6 = v6
publicConfig.getProperty("k7",null);//k7 = v7
应用B获取Apollo配置
//application
Config appConfig = ConfigService.getAppConfig();
appConfig.getProperty("k1",null);//k1 = v11
appConfig.getProperty("k2",null);//k2 = null
appConfig.getProperty("k3",null);//k3 = v32

//NS-Private,由于没有NS-Private Namespace 所以获取到default value
Config privateConfig = ConfigService.getConfig("NS-Private");
privateConfig.getProperty("k1",null);//k1 = v3

//NS-Public
Config publicConfig = ConfigService.getConfig("NS-Public");
publicConfig.getProperty("k4",null);//k4 = v5 cover
publicConfig.getProperty("k6",null);//k6 = v6
publicConfig.getProperty("k7",null);//k7 = v7
应用C获取Apollo配置
//application
 Config appConfig = ConfigService.getAppConfig();
 appConfig.getProperty("k1", null); // k1 = v12
 appConfig.getProperty("k2", null); // k2 = null
 appConfig.getProperty("k3", null); // k3 = v33
  
 //NS-Private,由于没有NS-Private Namespace 所以获取到default value
 Config privateConfig = ConfigService.getConfig("NS-Private");
 privateConfig.getProperty("k1", "default value"); 
  
 //NS-Public,公共类型的Namespace,任何项目都可以获取到
 Config publicConfig = ConfigService.getConfig("NS-Public");
 publicConfig.getProperty("k4", null); // k4 = v5
 publicConfig.getProperty("k6", null); // k6 = v6
 publicConfig.getProperty("k7", null); // k7 = v7
ChangeListener

以上代码列子中可以看到,在客户端Namespace映射成一个Config对象。Namespace配置变更的监听器是注册在Config对象上。

所以在应用A中监听application的Namespace代码如下:

Config appConfig = ConfigService.getAppConfig();
appConfig.addChangeListener(new ConfigChangeListener() {
  public void onChange(ConfigChangeEvent changeEvent) {
    //do something
  }
})

在应用A中监听NS-Private的Namespace代码如下:

Config privateConfig = ConfigService.getConfig("NS-Private");
privateConfig.addChangeListener(new ConfigChangeListener() {
  public void onChange(ConfigChangeEvent changeEvent) {
    //do something
  }
})

在应用A、应用B、应用C中监听NS-Public的Namespace代码如下:

Config publicConfig = ConfigService.getConfig("NS-Public");
publicConfig.addChangeListener(new ConfigChangeListener() {
  public void onChange(ConfigChangeEvent changeEvent) {
    //do something
  }
})