apollo配置中心

这是我参与更文挑战的第16天

apollo配置中心

1.历史

Apollo是携程框架部门研发的分布式陪配置中心,能够集中化管理应用,即不同环境、不同集群的配置。配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

服务端基于spring Boot和spring Cloud开发,打包后可以直接运行,不需要额外安装Tomcat等应用容器。

Java客户端不依赖任何框架,能够运行于所有Java运行时环境,同时对Spring/Spring Boot环境也有较好的支持。

.Net客户端不依赖任何框架,能够运行于所有.Net运行时环境。

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

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

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

1.链接

官方Gitee

官方GitHub

2.部署

用于多个微服务配置文件的统一管理。

portal:后台配置管理页面;

config:提供配置的读取、推送等功能;

admin:提供配置的修改、发布等功能

  1. 使用官方的网站已经发版好的包直接构建会比较快些,即发行版。在github上有发行版,在gitee上可能找不到。
# 将下面三个文件下载拷贝到linux服务器上
apollo-portal-1.7.1-github, apollo-configservice-1.7.1-github, apollo-adminservice-1.7.1-github
# 修改数据库连接地址, 在configservice中, 修改jdbc后面的地址即可。并且修改账户
vim application-github.properties
# 使用apollo的sql创建相应的数据, 在指导文件中的apollo-quick-start中, 先使用
# apolloconfigdb.sql创建数据库
apolloconfigdb.sql, apolloportaldb.sql
# 创建之后启动configservice的jar包, 此时可能会报错, 小坑
The server time zone value 'xxxxx(一串乱码)', 
# 修改config中的编码即可, 添加如下字段
characterEncoding=utf8&serverTimezone=Asia/Shanghai
# 之后还会报一个错,这是因为eureka没有起来, 他自己注册自己, 没有办法注册, 在eureka启动
# 之后, 自己注册自己成功即可, 即出现Started Eureka Server字段
java -jar xxx.jar
com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
# 之后启动adminservice
java -jar xxx.jar
# 由于防火墙的原因, 导致eureka网页不能访问
# 使用命令查看防火墙状态
systemctl status firewalld
# 查看相应端口是否有访问权限
firewall-cmd --query-port=8080/tcp
# 如果没有, 添加相应的端口权限, 永久生效还需要添加  --permanent 参数

firewall-cmd --permanent --add-port=80/tcp
# 也可以移除
firewall-cmd --permanent --remove-port=8080/tcp
# 修改配置后要重启防火墙
firewall-cmd --reload
# 参数解释
1、firwall-cmd:是Linux提供的操作firewall的一个工具;
2、--permanent:表示设置为持久;
3、--add-port:标识添加的端口;
# 修改portal的配置文件, 同样是数据库的地址\用户\密码\编码风格
application-github.properties
# 修改apollo-env.properties, 只留下开发的环境, 剩余的是预发\生产等环境
	local.meta=http://localhost:8080
	dev.meta=http://localhost:8080
	#dev.meta=http://fill-in-dev-meta-server:8080
	#fat.meta=http://fill-in-fat-meta-server:8080
	#uat.meta=http://fill-in-uat-meta-server:8080
	#lpt.meta=${lpt_meta}
	#pro.meta=http://fill-in-pro-meta-server:8080
# 启动之后在网页访问 ip+端口号, 账户是apollo, 密码admin
# 如果要修改项目管理, 此时只能到数据库中修改, 网页没有添加或者修改的
# 在ApolloPortalDB数据库中organizations添加
复制代码

之后的就是对项目的CRUD等等。然后配置是一组key-value形式

1.应用

spring-boot项目

依赖:

<!-- https://mvnrepository.com/artifact/com.ctrip.framework.apollo/apollo-client -->
<dependency>
    <groupId>com.ctrip.framework.apollo</groupId>
    <artifactId>apollo-client</artifactId>
    <version>1.7.0</version>
</dependency>
复制代码

application.properties中添加下面配置

app.id=001

spring.application.name=provider
apollo.meta=http://192.168.40.131:8080
apollo.bootstrap.enabled=true
apollo.bootstrap.namespaces=application
复制代码

启动项目直接访问地址即可。

但是使用bootstrap.yml的配置是无法启动的, 配置文件无法生效,导致无法从apollo上拉取服务, 不知道啥原因。使用application.yml报错无法从appId:1上拉取服务, 而我们的app.id是001, 不匹配肯定拉取不到。这是apollo的决定的。详细报错如下图

Sync config failed, will retry. Repository class com.ctrip.framework.apollo.internals.RemoteConfigRepository, reason: Load Apollo Config failed - appId: 1
复制代码

apolloapp.id不能以0开头

有时候, 更改不需要马上生效, 我们需要手动控制配置, 此时就不能使用上述全局的监听。 解决方法如下apollo

@Bean
public void config() {
    // config instance is singleton for each namespace and is never null
    Config config = ConfigService.getAppConfig();
    config.addChangeListener(changeEvent -> {
        System.out.println("Changes for namespace " + changeEvent.getNamespace());
        for (String key : changeEvent.changedKeys()) {
            ConfigChange change = changeEvent.getChange(key);
            System.out.println(String.format("Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s", change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType()));
        }
    });
}
复制代码

3.原理

  1. 针对一组服务,会有一个app.id用于区分不同的服务组,即唯一标识。下图所示: app.id=mall,这一组的微服务名称是mall,不同的服务组,app.id肯定是不一样的了。那么服务配置放到哪里?像spring Cloud是放到git上的,但是缺陷是没有一整套流程管理,如对配置文件的CRUD,且没有相应的UI界面进行操作,只能使用git的客户端进行操作。

  2. apollonacos则将配置文件放入了mysql中。当配置文件被修改,apollo会通过MQ进行通知应用程序,配置文件已修改,至于服务怎么处理,此时就不是配置中心该去操心的事情了。

  3. MQ集成了BUS组件,BUS底层又集成了EIP(企业级消息集成)

问题1:如果项目启动的时候,因为一些外力因素,比如网路延时等,导致配置中心没有连接上,该怎么处理?(高可用)

在项目启动的时候,设置一个默认值并缓存,然后在后续连接上apollo的时候将最后一次更新的值放入缓存中。

然而缓存带来的问题就是, 服务down后, 客户仍然可以访问, 并且可以拿到值

问题2:如果一直连不上,一直缓存,怎么解决?

apollo中,每一个服务节点,都有不同的角色。

  1. admin: 用来对所有的配置文件进行crud
  2. portal:相当于一个前端UI界面
  3. configconfig server相当与一个推销员,在config发生变化时,会向应用服务推送消息。然后应用服务在收到消息后,会在config服务中找相应的配置文件。在config中集成了eureka的注册发现功能

小结:所以一般高可用,需要配置adminconfig

在这里插入图片描述

apollo的总体设计

在这里插入图片描述

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

  • Config Service提供配置的读取、推送等功能,服务对象是Apollo客户端
  • Admin Service提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面)
  • Config ServiceAdmin Service都是多实例、无状态部署,所以需要将自己注册到Eureka中并保持心跳
  • 在Eureka之上我们架了一层Meta Server用于封装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进程中

1.apollo基础模型

在这里插入图片描述

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

2.客户端设计

在这里插入图片描述

上图简要描述了Apollo客户端的实现原理:

  1. 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。

    1. 长连接实际上我们是通过Http Long Polling实现的,具体而言:

      • 客户端发起一个Http请求到服务端
      • 服务端会保持住这个连接60秒
        • 如果在60秒内有客户端关心的配置变化,被保持住的客户端请求会立即返回,并告知客户端有配置变化的namespace信息,客户端会据此拉取对应namespace的最新配置
        • 如果在60秒内没有客户端关心的配置变化,那么会返回Http状态码304给客户端
      • 客户端在收到服务端请求后会立即重新发起连接,回到第一步

      考虑到会有数万客户端向服务端发起长连,在服务端我们使用了async servlet(Spring DeferredResult)来服务Http Long Polling请求。

  2. 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。

    • 这是一个fallback机制,为了防止推送机制失效导致配置不更新
    • 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 – Not Modified
    • 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。
  3. 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中

  4. 客户端会把从服务端获取到的配置在本地文件系统缓存一份

    • 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置
  5. 应用程序从Apollo客户端获取最新的配置、订阅配置更新通知

3.可用性考虑

配置中心作为基础服务,可用性要求非常高,下面的表格描述了不同场景下Apollo的可用性:

场景 影响 降级 原因
某台config service下线 无影响 Config service无状态,客户端重连其它config service
所有config service下线 客户端无法读取最新配置,Portal无影响 客户端重启时,可以读取本地缓存配置文件
某台admin service下线 无影响 Admin service无状态,Portal重连其它admin service
所有admin service下线 客户端无影响,portal无法更新配置
某台portal下线 无影响 Portal域名通过slb绑定多台服务器,重试后指向可用的服务器
全部portal下线 客户端无影响,portal无法更新配置
某个数据中心下线 无影响 多数据中心部署,数据完全同步,Meta Server/Portal域名通过slb自动切换到其它存活的数据中心
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享