个人 二维码




公众号二维码

name - artist
00:00

      目录

      Spring Cloud 系列之 Apollo 配置中心

      目录

      背景

        

      /resources/articles/spring/spring-cloud/apollo/apollo.jpg

      /resources/articles/spring/spring-cloud/apollo/image-20200327115131541.png

        

        随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址等等。

        对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制等等。

        在这样的大环境下,传统的通过配置文件、数据库等方式已经越来越无法满足开发人员对配置管理的需求。

        Apollo 配置中心应运而生!Apollo - 一个可靠的配置管理系统。

        

      Apollo 介绍

        

        Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。服务端基于 Spring Boot 和 Spring Cloud 开发,打包后可以直接运行,不需要额外安装 Tomcat 等应用容器。

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

      1. application (应用)
      2. environment (环境)
      3. cluster (集群)
      4. namespace (命名空间 Namespace 是配置项的集合,类似于一个配置文件的概念)

        同时,Apollo 基于开源模式开发,开源地址:https://github.com/ctripcorp/apollo

        官网文档:https://github.com/ctripcorp/apollo/wiki/Quick-Start

        演示环境(Demo):

      • http://106.54.227.205/
      • 账号/密码:apollo/admin

      /resources/articles/spring/spring-cloud/apollo/apollo-home-screenshot.jpg

      上图是Apollo配置中心中一个项目的配置首页

      • 在页面左上方的环境列表模块展示了所有的环境和集群,用户可以随时切换。
      • 页面中央展示了两个namespace(application和FX.apollo)的配置信息,默认按照表格模式展示、编辑。用户也可以切换到文本模式,以文件形式查看、编辑。
      • 页面上可以方便地进行发布、回滚、灰度、授权、查看更改历史和发布历史等操作。

        

      Apollo 核心概念

        

      1. application (应用)
        • 这个很好理解,就是实际使用配置的应用,Apollo客户端在运行时需要知道当前应用是谁,从而可以去获取对应的配置
        • 每个应用都需要有唯一的身份标识 – appId,我们认为应用身份是跟着代码走的,所以需要在代码中配置,具体信息请参见Java客户端使用指南
      2. environment (环境)
        • 配置对应的环境,Apollo客户端在运行时需要知道当前应用处于哪个环境,从而可以去获取应用的配置
        • 我们认为环境和代码无关,同一份代码部署在不同的环境就应该能够获取到不同环境的配置
        • 所以环境默认是通过读取机器上的配置(server.properties中的env属性)指定的,不过为了开发方便,我们也支持运行时通过System Property等指定,具体信息请参见Java客户端使用指南
      3. cluster (集群)
        • 一个应用下不同实例的分组,比如典型的可以按照数据中心分,把上海机房的应用实例分为一个集群,把北京机房的应用实例分为另一个集群。
        • 对不同的cluster,同一个配置可以有不一样的值,如zookeeper地址。
        • 集群默认是通过读取机器上的配置(server.properties中的idc属性)指定的,不过也支持运行时通过System Property指定,具体信息请参见Java客户端使用指南
      4. namespace (命名空间)
        • 一个应用下不同配置的分组,可以简单地把namespace类比为文件,不同类型的配置存放在不同的文件中,如数据库配置文件,RPC配置文件,应用自身的配置文件等
        • 应用可以直接读取到公共组件的配置namespace,如DAL,RPC等
        • 应用也可以通过继承公共组件的配置namespace来对公共组件的配置做调整,如DAL的初始数据库连接数

        

      Apollo 特性

        

      • 统一管理不同环境、不同集群的配置
        • Apollo提供了一个统一界面集中式管理不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)的配置。
        • 同一份代码部署在不同的集群,可以有不同的配置,比如zk的地址等
        • 通过命名空间(namespace)可以很方便的支持多个不同应用共享同一份配置,同时还允许应用对共享的配置进行覆盖
        • 配置界面支持多语言(中文,English)
      • 配置修改实时生效(热发布)
        • 用户在Apollo修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序。
      • 版本发布管理
        • 所有的配置发布都有版本概念,从而可以方便的支持配置的回滚。
      • 灰度发布
        • 支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一段时间没问题后再推给所有应用实例。
      • 权限管理、发布审核、操作审计
        • 应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误。
        • 所有的操作都有审计日志,可以方便的追踪问题。
      • 客户端配置信息监控
        • 可以方便的看到配置在被哪些实例使用
      • 提供Java和.Net原生客户端
        • 提供了Java和.Net的原生客户端,方便应用集成
        • 支持Spring Placeholder,Annotation和Spring Boot的ConfigurationProperties,方便应用使用(需要Spring 3.1.1+)
        • 同时提供了Http接口,非Java和.Net应用也可以方便的使用
      • 提供开放平台API
        • Apollo自身提供了比较完善的统一配置管理界面,支持多环境、多数据中心配置管理、权限、流程治理等特性。
        • 不过Apollo出于通用性考虑,对配置的修改不会做过多限制,只要符合基本的格式就能够保存。
        • 在我们的调研中发现,对于有些使用方,它们的配置可能会有比较复杂的格式,如xml, json,需要对格式做校验。
        • 还有一些使用方如DAL,不仅有特定的格式,而且对输入的值也需要进行校验后方可保存,如检查数据库、用户名和密码是否匹配。
        • 对于这类应用,Apollo支持应用方通过开放接口在Apollo进行配置的修改和发布,并且具备完善的授权和权限控制
      • 部署简单
        • 配置中心作为基础服务,可用性要求非常高,这就要求Apollo对外部依赖尽可能地少
        • 目前唯一的外部依赖是MySQL,所以部署非常简单,只要安装好Java和MySQL就可以让Apollo跑起来
        • Apollo还提供了打包脚本,一键就可以生成所有需要的安装包,并且支持自定义运行时参数

        

      Apollo 总体设计

        

        官方文档:https://github.com/ctripcorp/apollo/wiki/Apollo配置中心设计

        

      架构模块

        

      /resources/articles/spring/spring-cloud/apollo/overall-architecture.png

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

      • Config Service提供配置的读取、推送等功能,服务对象是Apollo客户端
      • Admin Service提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面)
      • Config Service和Admin 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.3 各模块概要介绍

        

      1.3.1 Config Service

        

      • 提供配置获取接口
      • 提供配置更新推送接口(基于Http long polling)
        • 服务端使用Spring DeferredResult实现异步化,从而大大增加长连接数量
        • 目前使用的tomcat embed默认配置是最多10000个连接(可以调整),使用了4C8G的虚拟机实测可以支撑10000个连接,所以满足需求(一个应用实例只会发起一个长连接)。
      • 接口服务对象为Apollo客户端

        

      1.3.2 Admin Service

        

      • 提供配置管理接口
      • 提供配置修改、发布等接口
      • 接口服务对象为Portal

        

      1.3.3 Meta Server

        

      • Portal通过域名访问Meta Server获取Admin Service服务列表(IP+Port)
      • Client通过域名访问Meta Server获取Config Service服务列表(IP+Port)
      • Meta Server从Eureka获取Config Service和Admin Service的服务信息,相当于是一个Eureka Client
      • 增设一个Meta Server的角色主要是为了封装服务发现的细节,对Portal和Client而言,永远通过一个Http接口获取Admin Service和Config Service的服务信息,而不需要关心背后实际的服务注册和发现组件
      • Meta Server只是一个逻辑角色,在部署时和Config Service是在一个JVM进程中的,所以IP、端口和Config Service一致

        

      1.3.4 Eureka

        

      • 基于EurekaSpring Cloud Netflix提供服务注册和发现
      • Config Service和Admin Service会向Eureka注册服务,并保持心跳
      • 为了简单起见,目前Eureka在部署时和Config Service是在一个JVM进程中的(通过Spring Cloud Netflix)

        

      1.3.5 Portal

        

      • 提供Web界面供用户管理配置
      • 通过Meta Server获取Admin Service服务列表(IP+Port),通过IP+Port访问服务
      • 在Portal侧做load balance、错误重试

        

      1.3.6 Client

        

      • Apollo提供的客户端程序,为应用提供配置获取、实时更新等功能
      • 通过Meta Server获取Config Service服务列表(IP+Port),通过IP+Port访问服务
      • 在Client侧做load balance、错误重试

        

      服务端

        

      /resources/articles/spring/spring-cloud/apollo/release-message-notification-design.png

      上图简要描述了配置发布的大致过程:

      1. 用户在Portal操作配置发布
      2. Portal调用Admin Service的接口操作发布
      3. Admin Service发布配置后,发送ReleaseMessage给各个Config Service
      4. Config Service收到ReleaseMessage后,通知对应的客户端

        

      客户端

        

      /resources/articles/spring/spring-cloud/apollo/client-architecture.png

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

      1. 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。(通过Http Long Polling实现)
      2. 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。
        • 这是一个fallback机制,为了防止推送机制失效导致配置不更新
        • 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified
        • 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。
      3. 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中
      4. 客户端会把从服务端获取到的配置在本地文件系统缓存一份
        • 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置
      5. 应用程序可以从Apollo客户端获取最新的配置、订阅配置更新通知

        

      环境准备

        

      Java

        

      • Apollo 服务端:1.8+
      • Apollo 客户端:1.7+

      由于需要同时启动服务端和客户端,所以建议安装Java 1.8+。

        

      MySQL

        

      • 版本要求:5.6.5+

      Apollo的表结构对timestamp使用了多个default声明,所以需要5.6.5以上版本。

        

      下载Quick Start安装包

        

        Apollo 给我们准备好了一个Quick Start安装包,大家只需要下载到本地,就可以直接使用,免去了编译、打包过程。

        安装包共50M,如果访问github网速不给力的话,可以从百度网盘下载。

      1. 从Github下载
      2. 从百度网盘下载
      3. 为啥安装包要58M这么大?
        • 因为这是一个可以自启动的jar包,里面包含了所有依赖jar包以及一个内置的tomcat容器

        

      安装 Apollo

        

      创建数据库

        

        Apollo 服务端共需要两个数据库:ApolloPortalDBApolloConfigDB,我们把数据库、表的创建和样例数据都分别准备了 sql 文件,只需要导入数据库即可。

      注意:如果你本地已经创建过Apollo数据库,请注意备份数据。我们准备的sql文件会清空Apollo相关的表。

        

      创建 ApolloPortalDB 数据库

        

        通过各种MySQL客户端导入sql/apolloportaldb.sql即可。

        

      创建 ApolloConfigDB 数据库

        

        通过各种MySQL客户端导入sql/apolloconfigdb.sql即可。

        

      配置数据库连接信息

        

        Apollo 服务端需要知道如何连接到你前面创建的数据库,所以需要编辑demo.sh,修改 ApolloPortalDB 和 ApolloConfigDB 相关的数据库连接串信息。

      注意:填入的用户需要具备对 ApolloPortalDB 和 ApolloConfigDB 数据的读写权限。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      #apollo config db info
      apollo_config_db_url=jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8
      apollo_config_db_username=用户名
      apollo_config_db_password=密码(如果没有密码,留空即可)
      
      # apollo portal db info
      apollo_portal_db_url=jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8
      apollo_portal_db_username=用户名
      apollo_portal_db_password=密码(如果没有密码,留空即可)
      

      注意:不要修改 demo.sh 的其它部分

        

      搭建服务端

        

      确保端口未被占用

        

        Quick Start脚本会在本地启动3个服务,分别使用8070, 8080, 8090端口,请确保这3个端口当前没有被使用。

        

      执行启动脚本

        

      1
      
      ./demo.sh start
      

        Apollo 提供的脚本文件为 .sh 文件,如果你的安装环境是在 Linux 系统下直接运行以上命令即可,如果你想在 Windows 环境下运行该脚本,先安装 Git 然后在 demo.sh 所在目录下鼠标右键点击 Git Bash Here,然后再通过以上命令运行脚本即可。

      /resources/articles/spring/spring-cloud/apollo/image-20200327132025298.png

        

        当看到如下输出后,就说明启动成功了!

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      
      ==== starting service ====
      Service logging file is ./service/apollo-service.log
      Started [10768]
      Waiting for config service startup.......
      Config service started. You may visit http://localhost:8080 for service status now!
      Waiting for admin service startup....
      Admin service started
      ==== starting portal ====
      Portal logging file is ./portal/apollo-portal.log
      Started [10846]
      Waiting for portal startup......
      Portal started. You can visit http://localhost:8070 now!
      

        

      异常排查

        

        如果启动遇到了异常,可以分别查看 service 和 portal 目录下的 log 文件排查问题。

      注:在启动 apollo-configservice 的过程中会在日志中输出 eureka 注册失败的信息,如com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused。需要注意的是,这个是预期的情况,因为 apollo-configservice 需要向 Meta Server(它自己)注册服务,但是因为在启动过程中,自己还没起来,所以会报这个错。后面会进行重试的动作,所以等自己服务起来后就会注册正常了。

        

      访问

        

        访问:http://localhost:8070/ Quick Start 集成了 Spring Security,输入用户名 apollo,密码 admin 后登录。

      /resources/articles/spring/spring-cloud/apollo/image-20200327132624380.png

        

        登录成功后,首页如下,Apollo 还提供了一个 SampleApp 样本案例供我们学习使用。

      /resources/articles/spring/spring-cloud/apollo/image-20200327132734543.png

        

      创建项目

        

        点击对应按钮创建项目。

      /resources/articles/spring/spring-cloud/apollo/image-20200327151648043.png

        

        这里先通过默认的样例部门演示(后面我会讲如何添加部门),AppId 对应客户端配置文件中 app.id。

      /resources/articles/spring/spring-cloud/apollo/image-20200327151850696.png

        

        创建成功如下图。

      /resources/articles/spring/spring-cloud/apollo/image-20200327154108245.png

        

      客户端接入服务端

        

        下面通过最常用、便捷的方式,即基于 Spring Boot 的集成方式来接入服务端。

        apollo-demo 聚合工程。Spring Boot 2.2.4.RELEASE

      • order-service:订单服务,端口 9090
      • order-service02:订单服务,端口 9091

        

      添加依赖

        

      1
      2
      3
      4
      5
      6
      
      <!-- https://mvnrepository.com/artifact/com.ctrip.framework.apollo/apollo-client -->
      <dependency>
          <groupId>com.ctrip.framework.apollo</groupId>
          <artifactId>apollo-client</artifactId>
          <version>1.6.0</version>
      </dependency>
      

        

      配置文件

        

        order-serviceorder-service02 的配置信息除端口外一致。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      
      server:
        port: 9090 # 端口
      
      spring:
        application:
          name: order-service # 应用名称
      
      # apollo 相关配置
      app:
        id: order-service # 与 Apollo 配置中心中的 AppId 一致
      
      apollo:
        meta: http://localhost:8080 # Apollo 中的 Eureka 注册中心地址
        #cluster:  # 指定 Apollo 集群,相同集群实例使用对应集群的配置
        #cacheDir:  # 配置缓存目录,网络不可用时任然可提供配置服务
        bootstrap:
          enable: true # 启用 apollo
      
      env: DEV # 指定环境
      
      # 自定义配置
      name: order-service-dev
      mysql:
        host: localhost
        port: 3306
        username: root
        password: root
      

        

      配置文件实体类

        

        order-serviceorder-service02 的配置文件实体类代码一致。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      
      package com.example.config;
      
      import lombok.AllArgsConstructor;
      import lombok.Data;
      import lombok.NoArgsConstructor;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.stereotype.Component;
      
      @Component
      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      public class ConfigProperties {
      
          @Value("${name}")
          private String name;
          @Value("${mysql.host}")
          private String mysqlHost;
          @Value("${mysql.port}")
          private Integer mysqlPort;
          @Value("${mysql.username}")
          private String mysqlUsername;
          @Value("${mysql.password}")
          private String mysqlPassword;
      
      }
      

        

      控制层

        

        order-serviceorder-service02 的控制层代码一致。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      
      package com.example.controller;
      
      import com.example.config.ConfigProperties;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.Map;
      
      @RestController
      public class ConfigController {
      
          @Autowired
          private ConfigProperties configProperties;
      
          @Value("${name}")
          private String name;
      
          @GetMapping("/name")
          public String getName() {
              return configProperties.getName();
          }
      
          @GetMapping("/mysql")
          public Map<Object, Object> getMySQLProperties() {
              // JDK9中的新特性,快速创建只读集合。
              return Map.of("host", configProperties.getMysqlHost(),
                      "port", configProperties.getMysqlPort(),
                      "username", configProperties.getMysqlUsername(),
                      "password", configProperties.getMysqlPassword());
          }
      
      }
      

        

      启动类

        

        启动类需要添加 @EnableApolloConfig 注解。

        order-serviceorder-service02 的启动类代码一致。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      
      package com.example;
      
      import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      
      @EnableApolloConfig
      @SpringBootApplication
      public class OrderServiceApplication {
      
          public static void main(String[] args) {
              SpringApplication.run(OrderServiceApplication.class, args);
          }
      
      }
      

        

      测试

        

      修改配置信息前

        

        访问:http://localhost:9090/name 和 http://localhost:9091/name 结果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200327160427847.png

      /resources/articles/spring/spring-cloud/apollo/image-20200327160848500.png

        

        访问:http://localhost:9090/mysql 和 http://localhost:9091/mysql 结果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200327171740031.png

      /resources/articles/spring/spring-cloud/apollo/image-20200327171811694.png

        

      新增配置信息

        

        进入项目后点击右上角的 新增配置

      /resources/articles/spring/spring-cloud/apollo/image-20200327161205042.png

        

        添加配置项 namemysql.usernamemysql.password

      /resources/articles/spring/spring-cloud/apollo/image-20200327161531659.png

      /resources/articles/spring/spring-cloud/apollo/image-20200327171928913.png

      /resources/articles/spring/spring-cloud/apollo/image-20200327172016524.png

        

      发布配置信息

        

        将刚才添加的配置信息批量发布至应用。

      /resources/articles/spring/spring-cloud/apollo/image-20200327172320579.png

      /resources/articles/spring/spring-cloud/apollo/image-20200327172427906.png

      /resources/articles/spring/spring-cloud/apollo/image-20200327172513672.png

        

      修改配置信息后

        

        控制台打印信息如下:

      1
      2
      3
      
      c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: order-service-dev-2.0, key: name, beanName: configController, field: com.example.controller.ConfigController.name
      c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: root123, key: mysql.password, beanName: configProperties, field: com.example.config.ConfigProperties.mysqlPassword
      c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: root123, key: mysql.username, beanName: configProperties, field: com.example.config.ConfigProperties.mysqlUsername
      

        

        访问:http://localhost:9090/name 和 http://localhost:9091/name 结果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200327172613277.png

      /resources/articles/spring/spring-cloud/apollo/image-20200327172632121.png

        

        访问:http://localhost:9090/mysql 和 http://localhost:9091/mysql 结果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200327172703604.png

      /resources/articles/spring/spring-cloud/apollo/image-20200327172722379.png

        以上只是 Apollo 的入门教程,后面我们会学习 Apollo 的更多高级玩法,比如多环境部署,高可用环境搭建等等。

        

      部门及用户管理

        

        接下来我们深入学习一下 Apollo 控制台的使用,刚才我们是通过样例部门和 Apollo 用户来操作的,可以自定义部门和用户吗?答案当然是可以的。下面我们就讲一下如何自定义部门和用户,如何给项目指定用户并分配权限以及删除应用。

        

      应用配置

        

        点击管理员工具下的系统参数菜单进入应用配置页面。

      /resources/articles/spring/spring-cloud/apollo/image-20200529114611782.png

        

        在应用配置页面通过organizations关键字查询部门信息,下图为默认信息。

      /resources/articles/spring/spring-cloud/apollo/image-20200529115028378.png

        

        在value一栏中添加自定义部门信息,点击保存,无特殊说明则修改完一分钟实时生效。

      /resources/articles/spring/spring-cloud/apollo/image-20200529161713572.png

        

        此时再去创建项目时,就可以选择我们刚才添加的部门了。

      /resources/articles/spring/spring-cloud/apollo/image-20200529161828736.png

        

      用户管理

        

        点击管理员工具下的用户管理菜单进入用户管理页面。

      /resources/articles/spring/spring-cloud/apollo/image-20200529131537277.png

        

        填写用户信息,点击提交,无特殊说明则修改完一分钟实时生效。

      /resources/articles/spring/spring-cloud/apollo/image-20200529131900664.png

        

        此时再去创建项目时,就可以选择我们刚才添加的用户了。如下图,我们给 product-service 项目分配了负责人 zhangsan,如果使用zhangsan登录的话,则只能看到他自己负责的项目。而 apollo 用户是超级管理员所以可以看到所有项目。

      /resources/articles/spring/spring-cloud/apollo/image-20200529161948650.png

        

      权限分配

        

        进入项目后点击右上角的授权按钮,进入权限管理页面。

      /resources/articles/spring/spring-cloud/apollo/image-20200529133818690.png

        

        可以给指定用户添加对该应用的修改权发布权,比如 order-service 是 apollo 创建的,但是我授权给了 zhangsan,zhangsan 再登录时也就可以操作这个项目了。

      /resources/articles/spring/spring-cloud/apollo/image-20200529134035194.png

        

      删除应用(项目)

        

        点击管理员工具下的删除应用、集群、AppNamespace菜单进入对应页面。

      /resources/articles/spring/spring-cloud/apollo/image-20200529133455056.png

        

        在删除应用栏目中的 AppId 处填写应用 id 先进行查询,查询到应用后点击删除应用即可。

      /resources/articles/spring/spring-cloud/apollo/image-20200529133559442.png

        

      配置管理

        

        这一小节我们通过大量配图演示如何增改删配置信息,以及如何添加 Namespace。

        

      添加配置

        

        进入项目后点击右上角的 新增配置

      /resources/articles/spring/spring-cloud/apollo/image-20200327161205042.png

        

        添加配置项信息,点击提交即可,刚添加的配置信息处于未发布状态。

      /resources/articles/spring/spring-cloud/apollo/image-20200529135707136.png

        

      修改配置

        

        点击对应配置项的修改按钮。

      /resources/articles/spring/spring-cloud/apollo/image-20200529135850787.png

        

        修改配置信息,也可填写修改说明,点击提交即可,更新后的信息如需生效要重新发布。

      /resources/articles/spring/spring-cloud/apollo/image-20200529140023551.png

        

      回滚

        

        回滚代表恢复至上一次的发布状态,比如刚刚发布的值是 order-service-2.0,回滚以后会恢复至上一次发布的 order-service。

      /resources/articles/spring/spring-cloud/apollo/image-20200530170249630.png

        

      删除配置

        

        点击对应配置项的删除按钮。

      /resources/articles/spring/spring-cloud/apollo/image-20200529141722626.png

        

        删除配置信息后如需生效要重新发布。

      /resources/articles/spring/spring-cloud/apollo/image-20200529141759441.png

        

      添加 Namespace

        

        如果配置项过多的情况下,可以通过 Namespace 来进行管理,Namespace 就相当于一份配置文件。

        进入项目后点击左下角添加Namespace

      /resources/articles/spring/spring-cloud/apollo/image-20200529142959857.png

        

        选择创建Namespace,类型这里需要说明一下:

      • public:公共配置,其他应用也可以使用;
      • private:私有配置,仅限本应用使用。

      /resources/articles/spring/spring-cloud/apollo/image-20200529145337483.png

        

        可以通过文本的方式添加多个配置项。

      /resources/articles/spring/spring-cloud/apollo/image-20200529151940934.png

      1
      2
      3
      4
      
      spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
      spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
      spring.datasource.username=root
      spring.datasource.password=1234
      

        

      测试

        

        客户端配置文件信息如下:

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      
      server:
        port: 9090 # 端口
      
      spring:
        application:
          name: order-service # 应用名称
      
      # apollo 相关配置
      app:
        id: order-service # 与 Apollo 配置中心中的 AppId 一致
      
      apollo:
        meta: http://localhost:8080 # Apollo 中的 Eureka 注册中心地址
        #cluster:  # 指定 Apollo 集群,默认为 default,相同集群实例使用对应集群的配置
        #cacheDir:  # 配置缓存目录,网络不可用时任然可提供配置服务
        bootstrap:
          enable: true # 启用 apollo
      
      env: DEV # 指定环境
      

        

      注解方式

        

        在启动类或配置类中添加 @EnableApolloConfig({"application", "application-mysql"}) 注解并指定 Namespace,就可以直接使用 Spring 的 @Value 注解来获取配置信息,${} 中对应 Apollo 中的 key,:后跟默认值。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      
      @Value("${spring.datasource.driver-class-name:}")
      private String driverClassName;
      @Value("${spring.datasource.url:}")
      private String url;
      @Value("${spring.datasource.username:root}")
      private String username;
      @Value("${spring.datasource.password:root}")
      private String password;
      
      @GetMapping("/datasourceByAnnotation")
      public Map<Object, Object> getDatasourceByAnnotation() {
          // JDK9中的新特性,快速创建只读集合。
          return Map.of("driverClassName", driverClassName,
                        "url", url,
                        "username", username,
                        "password", password);
      }
      

        访问:http://localhost:9090/datasourceByAnnotation 结果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200529154407842.png

        

      API方式

        

        我们可以通过以下代码读取 Apollo 中的配置信息。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      
      @GetMapping("/datasource")
      public Map<Object, Object> getDatasource() {
          //ConfigService.getAppConfig(); // 读取默认 Namespace
          // 读取指定 Namespace
          Config config = ConfigService.getConfig("application-mysql");
          // 获取配置信息,第一个参数为配置项的 key,第二个参数为默认值(读取不到配置就会使用默认值,建议都加上默认值)
          String driverClassName = config.getProperty("spring.datasource.driver-class-name", null);
          String url = config.getProperty("spring.datasource.url", null);
          String username = config.getProperty("spring.datasource.username", null);
          String password = config.getProperty("spring.datasource.password", null);
      
          // JDK9中的新特性,快速创建只读集合。
          return Map.of("driverClassName", driverClassName,
                        "url", url,
                        "username", username,
                        "password", password);
      }
      

        访问:http://localhost:9090/datasource 结果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200529154407842.png

        

      公共配置

        

        刚才添加 Namespace 时我们选择的是 private 私有配置,仅限本项目使用,如果有一些配置我们所有项目都需要使用,可以通过公共配置实现。

        

      添加公共配置

        

        比如我们先创建一个公共项目 common-service

      /resources/articles/spring/spring-cloud/apollo/image-20200529162142855.png

        

        然后创建公共的 Namespace。

      /resources/articles/spring/spring-cloud/apollo/image-20200529162322671.png

        

        添加配置信息提交并发布。

      /resources/articles/spring/spring-cloud/apollo/image-20200530145127905.png

        

        值得注意的是,公共配置信息是哪个项目创建的才拥有修改和删除的权力,其他项目只能选择关联和覆盖。

      /resources/articles/spring/spring-cloud/apollo/image-20200530145248528.png

        

      关联公共配置

        

        让 order-service 项目关联 common-service 的公共配置信息。

        进入项目后点击左下角添加Namespace,选择关联公共Namespace,添加刚才创建的公共Namespace。

      /resources/articles/spring/spring-cloud/apollo/image-20200529162734893.png

        

        关联成功以后在项目首页可以看到关联的配置信息,且只能选择覆盖此配置,不能删除和修改配置信息(可以删除Namespace)。或者直接在私有配置下配置同名的配置项,同名的私有配置会比公共配置优先级高。

      /resources/articles/spring/spring-cloud/apollo/image-20200530145446767.png

        

      测试

        

        在启动类或配置类中添加 @EnableApolloConfig({"application", "application-mysql", "microservice.application-common"}) 注解并指定 Namespace,就可以直接使用 Spring 的 @Value 注解来获取配置信息,${} 中对应 Apollo 中的 key,:后跟默认值。

      1
      2
      3
      4
      5
      6
      7
      
      @Value("${commonName:}")
      private String commonName;
      
      @GetMapping("/commonByAnnotation")
      public Map<Object, Object> getCommonByAnnotation() {
          return Map.of("commonName", commonName);
      }
      

        访问:http://localhost:9090/commonByAnnotation 结果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200530145634135.png

        

        我们可以通过以下的方式读取 Apollo 中的配置信息。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      @GetMapping("/common")
      public Map<Object, Object> getCommon() {
          //ConfigService.getAppConfig(); // 读取默认 Namespace
          // 读取指定 Namespace
          Config config = ConfigService.getConfig("microservice.application-common");
          // 获取配置信息,第一个参数为配置项的 key,第二个参数为默认值(读取不到配置就会使用默认值,建议都加上默认值)
          String commonName = config.getProperty("commonName", null);
          return Map.of("commonName", commonName);
      }
      

        访问:http://localhost:9090/common 结果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200530145634135.png

        

      集群管理

        

        在有些特殊情况下,比如部署在 A 机房的应用连接的 MySQL 服务器地址和部署在 B 机房的应用连接的 MySQL 服务器地址不一样。在这种情况下,可以通过在 Apollo 创建不同的集群来解决。

        

      添加集群

        

        进入项目后点击左下角添加集群,比如添加 SHAOY(欧阳数据中心)。

      /resources/articles/spring/spring-cloud/apollo/image-20200529165456967.png

        

      同步配置

        

        集群其实就是另一个环境而已,所有的操作和前面讲的都一样,这里就不再赘述。有一点需要说明一下,就是同步配置功能。

        假设 SHAOY 这个集群的配置信息和默认集群的配置信息只有个别地方不一致,大部分都是一致的,我们挨个添加岂不是很浪费时间?

        可以看到在 SHAOY 这个集群下的 application-mysql 的 Namespace 中是没有任何配置项的。不急,Apollo 给我们提供了一个同步配置的功能。通过同步配置功能,可以使多个环境、集群间的配置保持一致,需要注意的是,同步完之后需要发布后才会对应用生效。

        既然是将默认集群环境的配置同步至 SHAOY 环境中,那就在默认环境中选择需要同步的 Namespace,点击同步配置按钮。

      /resources/articles/spring/spring-cloud/apollo/image-20200529174413263.png

        

        勾选需要同步的配置,选择要同步到哪个集群,然后点击下一步。

      /resources/articles/spring/spring-cloud/apollo/image-20200529174511698.png

        

        点击同步按钮以后配置将同步成功,同步完之后需要发布后才会对应用生效。

      /resources/articles/spring/spring-cloud/apollo/image-20200529174616525.png

        

        数据已经同步过来了,我们根据需求修改了服务器地址为 192.168.10.101,然后发布配置。

      /resources/articles/spring/spring-cloud/apollo/image-20200529174956819.png

        

      测试

        

        配置文件中通过 apollo.cluster 指定集群名称。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      
      server:
        port: 9090 # 端口
      
      spring:
        application:
          name: order-service # 应用名称
      
      # apollo 相关配置
      app:
        id: order-service # 与 Apollo 配置中心中的 AppId 一致
      
      apollo:
        meta: http://localhost:8080 # Apollo 中的 Eureka 注册中心地址
        cluster: SHAOY # 指定 Apollo 集群,默认为 default,相同集群实例使用对应集群的配置
        #cacheDir:  # 配置缓存目录,网络不可用时任然可提供配置服务
        bootstrap:
          enable: true # 启用 apollo
      
      env: DEV # 指定环境
      
      # 自定义配置
      name: order-service-dev
      mysql:
        host: localhost
        port: 3306
        username: root
        password: root
      

        

        之前的代码无需做任何改变,访问:http://localhost:9090/datasourceByAnnotation 结果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200529175508712.png

        

      多环境部署方案

        

        为了让大家有更真实的感受,多环境部署方案我们在 Linux 环境下搭建,不再使用 Quick Start 脚本。

        当项目要上线部署到生产环境时,项目的配置比如数据库、缓存、队列等服务器的地址都会发生改变,这时候就需要通过 Apollo 为生产环境添加配置。目前 Apollo 预先定义的环境为:

      • DEV:Development environment 开发环境,用于开发者调试使用;
      • FAT:Feature Acceptance Test environment 功能验收测试环境,用于软件测试者测试使用;
      • UAT:User Acceptance Test environment 用户验收测试环境(仿真环境),用于生产环境下的软件测试者测试使用
      • PRO:Production environment 生产环境,最终上线环境。

        Apollo 也支持自定义环境。具体方式可以参考官方文档:https://github.com/ctripcorp/apollo/wiki/部署&开发遇到的常见问题#42-添加自定义的环境

        

        这里我们要明确一些信息:

      • Portal 部署在生产环境的机房,通过它来直接管理 FAT、UAT、PRO 等环境的配置即可;
      • Config Service、Admin Service 和 ApolloConfigDB 在每个环境都单独部署;
      • 应用需要配置指定的环境,默认为 DEV。

        总结下来就是:一套 Portal 可以管理多个环境,但是每个环境都需要独立部署一套 Config Service、Admin Service 和 ApolloConfigDB。

        服务器地址说明:

      • 192.168.10.101:apollo-portal,公共的 Portal
      • 192.168.10.102:DEV 环境,独立部署一套 Config Service、Admin Service,使用公共的 Portal
      • 192.168.10.103:PRO 环境,独立部署一套 Config Service、Admin Service,使用公共的 Portal

        

      创建数据库

        

      • 192.168.10.101 这台机器运行 apolloportaldb.sql 文件。
      • 192.168.10.102 和 192.168.10.103 都运行 apolloconfigdb.sql 文件。

        最终结果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200530000123069.png

        

      调整服务端配置

        

        Apollo 自身的一些配置是放在数据库里面的,所以需要针对实际情况做一些调整。

        配置项统一存储在 ApolloPortalDB.ServerConfig 表中,如下图,在③Value的地方添加环境即可,比如 dev,pro

      /resources/articles/spring/spring-cloud/apollo/image-20200530000531002.png

        

        或者也可以通过管理员工具 - 系统参数页面进行配置,通过 apollo.portal.envs 关键字查询并进行设置,无特殊说明则修改完一分钟实时生效。

      /resources/articles/spring/spring-cloud/apollo/image-20200529210151299.png

        

      下载安装包

        

        从GitHub Release页面下载最新版本的apollo-configservice-x.x.x-github.zipapollo-adminservice-x.x.x-github.zipapollo-portal-x.x.x-github.zip即可。本小节采用这种方式,可以省去本地打包的过程。

        如果需要对 Apollo 做定制开发,也可以选择通过源码构建:https://github.com/ctripcorp/apollo/wiki/分布式部署指南#222-通过源码构建 后面高可用环境的搭建我们就采用这种方式。

        

      配置数据库

        

        Apollo 服务端需要知道如何连接到你前面创建的数据库,数据库连接串信息位于上一步下载的压缩包中的config/application-github.properties中。

        

      配置 apollo-portal 的数据库连接信息

        

      1. 先将 apollo-portal-x.x.x-github.zip 上传至 192.168.10.101。
      2. 解压apollo-portal-x.x.x-github.zip
      3. 打开config目录下的application-github.properties文件
      4. 填写正确的 ApolloPortalDB 数据库连接串信息,注意用户名和密码后面不要有空格!
      5. 修改完的效果如下:
      1
      2
      3
      4
      
      # DataSource
      spring.datasource.url = jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8
      spring.datasource.username = root
      spring.datasource.password = 1234
      

        

      配置 apollo-configservice 的数据库连接信息

        

      1. apollo-configservice-x.x.x-github.zip 上传至 192.168.10.102 和 192.168.10.103
      2. 解压apollo-configservice-x.x.x-github.zip
      3. 打开config目录下的application-github.properties文件
      4. 填写正确的 ApolloConfigDB 数据库连接串信息,注意用户名和密码后面不要有空格!
      5. 修改完的效果如下:
      1
      2
      3
      4
      
      # DataSource
      spring.datasource.url = jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8
      spring.datasource.username = root
      spring.datasource.password = 1234
      

        

      配置 apollo-adminservice 的数据库连接信息

        

      1. apollo-adminservice-x.x.x-github.zip 上传至 192.168.10.102 和 192.168.10.103
      2. 解压apollo-adminservice-x.x.x-github.zip
      3. 打开config目录下的application-github.properties文件
      4. 填写正确的 ApolloConfigDB 数据库连接串信息,注意用户名和密码后面不要有空格!
      5. 修改完的效果如下:
      1
      2
      3
      4
      
      # DataSource
      spring.datasource.url = jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8
      spring.datasource.username = root
      spring.datasource.password = 1234
      

        

      配置 apollo-portal 的 meta service 信息

        

        Apollo Portal 需要在不同的环境访问不同的 meta service(apollo-configservice) 地址,所以我们需要在配置中提供这些信息。默认情况下,meta service 和 config service 是部署在同一个JVM进程,所以 meta service 的地址就是 config service 的地址。

      对于 1.6.0 及以上版本,可以通过 ApolloPortalDB.ServerConfig 中的配置项来配置 Meta Service 地址。

        

      新版本配置方式

        

        通过 apollo.portal.meta.servers 添加 meta service(apollo-configservice) 地址,类似以下方式,修改完需要重启生效。

      /resources/articles/spring/spring-cloud/apollo/image-20200530114346761.png

      1
      2
      3
      4
      
      {
          "DEV":"http://192.168.10.102:8080",
          "PRO":"http://192.168.10.103:8080"
      }
      

        

      旧版本配置方式

        

        打开apollo-portal-x.x.x-github.zipconfig目录下的apollo-env.properties文件。

        假设 DEV 的 apollo-configservice 未绑定域名,地址是 1.1.1.1:8080,FAT 的 apollo-configservice 绑定了域名 apollo.fat.xxx.com,UAT 的 apollo-configservice 绑定了域名 apollo.uat.xxx.com,PRO 的 apollo-configservice 绑定了域名 apollo.xxx.com,那么可以如下修改各环境 meta service 服务地址,格式为${env}.meta=http://${config-service-url:port},如果某个环境不需要,也可以直接删除对应的配置项,参考案例如下:

      1
      2
      3
      4
      
      dev.meta=http://1.1.1.1:8080
      fat.meta=http://apollo.fat.xxx.com
      uat.meta=http://apollo.uat.xxx.com
      pro.meta=http://apollo.xxx.com
      

        如果采用旧版本配置方式,本小节配置方案如下:

      1
      2
      3
      4
      5
      6
      
      #local.meta=http://localhost:8080
      dev.meta=http://192.168.10.102: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://192.168.10.103:8080
      

        除了通过apollo-env.properties方式配置 meta service 以外,apollo 也支持在运行时指定 meta service(优先级比apollo-env.properties高):

      1. 通过 Java System Property ${env}_meta
        • 可以通过 Java 的 System Property ${env}_meta来指定
        • java -Ddev_meta=http://config-service-url -jar xxx.jar
        • 也可以通过程序指定,如System.setProperty("dev_meta", "http://config-service-url");
      2. 通过操作系统的 System Environment ${ENV}_META
        • DEV_META=http://config-service-url
        • 注意 key 为全大写,且中间是_分隔

        

      启动

        

        三台机器都进入对应安装包的 script 目录,执行 startup.sh 文件。

        我的启动顺序为:

      • 192.168.10.101 启动 Portal
      • 192.168.10.102 启动 ConfigService 再启动 AdminService
      • 192.168.10.103 启动 ConfigService 再启动 AdminService

        

        先访问:192.168.10.102:8080 和 192.168.10.103:8080 看看 Eureka 以及各服务是否正常启动,如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200530085729365.png

      /resources/articles/spring/spring-cloud/apollo/image-20200530085804892.png

        

        再访问:192.168.10.101:8070 输入 Apollo/admin 进行登录,点击案例项目 SampleApp 进入项目首页,看到多环境说明搭建成功,后续的操作就和之前讲的一样了,这里就不再过多赘述。

      /resources/articles/spring/spring-cloud/apollo/image-20200530090046731.png

        

      高可用环境搭建

        

      分析

        

      数据库高可用

        

        方案很多,比如双主结构、主从结构、异地备份等等,还可以选择第三方云数据库服务,让云服务厂商去保证数据库的高可用性,这样不仅比自己实现起来更可靠、更轻松,而且还方便管理等。

        

      AdminService 高可用

        

        在 Apollo 中所有的 Admin Service 都会注册到 Eureka 里,所以我们只需要配置多台 AdminService,数据库采用同一套即可。

        

      ConfigService 高可用

        

        在 Apollo 的设计中每个 ConfigService 也是一个 Euerka 的注册中心,所以保证 ConfigService 高可用的前提是保证 Eureka 的高可用,Eureka 的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。

        

      实践

        

        再来一台机器 192.168.10.104 然后将 apollo-configservice-x.x.x-github.zipapollo-adminservice-x.x.x-github.zip 上传至该机器,解压以后都配置 102 机器的数据库,我们搭建一个 DEV 的高可用环境。

        

      配置数据库

        

      1. 将 ConfigService 和 AdminService 上传至 192.168.10.104
      2. 解压
      3. 打开config目录下的application-github.properties文件
      4. 填写正确的 ApolloConfigDB 数据库连接串信息,注意用户名和密码后面不要有空格!
      5. 修改完的效果如下:
      1
      2
      3
      4
      
      # DataSource
      spring.datasource.url = jdbc:mysql://192.168.10.102:3306/ApolloConfigDB?characterEncoding=utf8
      spring.datasource.username = root
      spring.datasource.password = 1234
      

        

      调整服务端配置

        

        Eureka 注册中心地址存储在 ApolloConfigDB.ServerConfig 表中,如下图,在③Value的地方添加多个地址即可。

      /resources/articles/spring/spring-cloud/apollo/image-20200530112059156.png

        

      配置 apollo-portal 的 meta service 信息

        

        Apollo Portal 需要在不同的环境访问不同的 meta service(apollo-configservice) 地址,所以我们需要在配置中提供这些信息。默认情况下,meta service 和 config service 是部署在同一个JVM进程,所以 meta service 的地址就是 config service 的地址。

      对于 1.6.0 及以上版本,可以通过 ApolloPortalDB.ServerConfig 中的配置项来配置 Meta Service 地址。

        

      新版本配置方式

        

        通过 apollo.portal.meta.servers 添加 meta service(apollo-configservice) 地址,类似以下方式,修改完需要重启生效。

      /resources/articles/spring/spring-cloud/apollo/image-20200530114529024.png

      1
      2
      3
      4
      
      {
          "DEV":"http://192.168.10.102:8080,http://192.168.10.104:8080",
          "PRO":"http://192.168.10.103:8080"
      }
      

        

      旧版本配置方式

        

        打开apollo-portal-x.x.x-github.zipconfig目录下的apollo-env.properties文件。

        假设 DEV 的 apollo-configservice 未绑定域名,地址是 1.1.1.1:8080,FAT 的 apollo-configservice 绑定了域名 apollo.fat.xxx.com,UAT 的 apollo-configservice 绑定了域名 apollo.uat.xxx.com,PRO 的 apollo-configservice 绑定了域名 apollo.xxx.com,那么可以如下修改各环境 meta service 服务地址,格式为${env}.meta=http://${config-service-url:port},如果某个环境不需要,也可以直接删除对应的配置项,参考案例如下:

      1
      2
      3
      4
      
      dev.meta=http://1.1.1.1:8080
      fat.meta=http://apollo.fat.xxx.com
      uat.meta=http://apollo.uat.xxx.com
      pro.meta=http://apollo.xxx.com
      

        如果采用旧版本配置方式,本小节配置方案如下:

      1
      2
      3
      4
      5
      6
      
      #local.meta=http://localhost:8080
      dev.meta=http://192.168.10.102:8080,http://192.168.10.104: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://192.168.10.103:8080
      

        除了通过apollo-env.properties方式配置 meta service 以外,apollo 也支持在运行时指定 meta service(优先级比apollo-env.properties高):

      1. 通过 Java System Property ${env}_meta
        • 可以通过 Java 的 System Property ${env}_meta来指定
        • java -Ddev_meta=http://config-service-url -jar xxx.jar
        • 也可以通过程序指定,如System.setProperty("dev_meta", "http://config-service-url");
      2. 通过操作系统的 System Environment ${ENV}_META
        • DEV_META=http://config-service-url
        • 注意 key 为全大写,且中间是_分隔

        

      启动

        

        进入对应安装包的 script 目录,执行 startup.sh 文件。

        我的启动顺序为:

      • 192.168.10.101 启动 Portal
      • 192.168.10.102 启动 ConfigService 再启动 AdminService
      • 192.168.10.104 启动 ConfigService 再启动 AdminService

        

        访问:192.168.10.102:8080 和 192.168.10.104:8080 看看 Eureka 以及各服务是否正常启动,如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200530113237856.png

        最后,在页面发布配置信息的同时,可以通过查看日志的方式,查看高可用环境是否搭建成功,日志存放在 /opt/appId/xxx.log

        

      灰度发布

        

        在一般情况下,升级服务器端应用,需要将应用源码或程序包上传到服务器,然后停止掉老版本服务,再启动新版本。但是这种简单的发布方式存在两个问题,一方面,在新版本升级过程中,服务是暂时中断的,另一方面,如果新版本有BUG,升级失败,回滚起来也非常麻烦,容易造成更长时间的服务不可用。

        为了解决这些问题,人们研究出了多种发布策略,比如蓝绿部署、滚动发布、灰度发布等,Apollo 采用的是灰度发布的特性。

        

      介绍

        

      /resources/articles/spring/spring-cloud/apollo/20494560798322.jpg

        灰度发布也叫金丝雀发布,起源是,矿井工人发现,金丝雀对瓦斯气体很敏感,矿工会在下井之前,先放一只金丝雀到井中,如果金丝雀不叫了,就代表瓦斯浓度高。

        在灰度发布开始后,先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进行线上测试,启动的这个新版本应用,就是我们的金丝雀。如果没有问题,那么可以将少量的用户流量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做各种数据对比,就是所谓的 A/B 测试。

        当确认新版本运行良好后,再逐步将更多的流量导入到新版本上,在此期间,还可以不断地调整新旧两个版本的运行的服务器副本数量,以使得新版本能够承受越来越大的流量压力。直到将100%的流量都切换到新版本上,最后关闭剩下的老版本服务,完成灰度发布。如果在灰度发布过程中(灰度期)发现了新版本有问题,就应该立即将流量切回老版本上,这样,就会将负面影响控制在最小范围内。

        

      实践

        

        我们使用 apollo-demo 中的 order-serviceorder-service02 两个实例来实践,order-service 在 Windows 端运行,order-service02 在 Linux 端运行。

        

      配置文件

        

        order-service 的配置文件。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      
      server:
        port: 9090 # 端口
      
      spring:
        application:
          name: order-service # 应用名称
      
      # apollo 相关配置
      app:
        id: order-service # 与 Apollo 配置中心中的 AppId 一致
      
      apollo:
        meta: http://192.168.10.102:8080,http://192.168.10.104:8080 # Apollo 中的 Eureka 注册中心地址
        #cluster: SHAOY # 指定 Apollo 集群,默认为 default,相同集群实例使用对应集群的配置
        #cacheDir:  # 配置缓存目录,网络不可用时任然可提供配置服务
        bootstrap:
          enable: true # 启用 apollo
      
      env: DEV # 指定环境
      
      # 自定义配置
      name: order-service-dev
      mysql:
        host: localhost
        port: 3306
        username: root
        password: root
      

        

        order-service02 的配置文件。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      
      server:
        port: 9091 # 端口
      
      spring:
        application:
          name: order-service # 应用名称
      
      # apollo 相关配置
      app:
        id: order-service # 与 Apollo 配置中心中的 AppId 一致
      
      apollo:
        meta: http://192.168.10.102:8080,http://192.168.10.104:8080 # Apollo 中的 Eureka 注册中心地址
        #cluster: SHAOY # 指定 Apollo 集群,默认为 default,相同集群实例使用对应集群的配置
        #cacheDir:  # 配置缓存目录,网络不可用时任然可提供配置服务
        bootstrap:
          enable: true # 启用 apollo
      
      env: DEV # 指定环境
      
      # 自定义配置
      name: order-service-dev
      mysql:
        host: localhost
        port: 3306
        username: root
        password: root
      

        

        最终效果如下:

      /resources/articles/spring/spring-cloud/apollo/image-20200530135138962.png

        

      创建灰度

        

        点击右上角灰度按钮,点击确定创建灰度。

      /resources/articles/spring/spring-cloud/apollo/image-20200530135630931.png

      /resources/articles/spring/spring-cloud/apollo/image-20200530135654582.png

        

      新增灰度配置

        

      /resources/articles/spring/spring-cloud/apollo/image-20200530135915234.png

      /resources/articles/spring/spring-cloud/apollo/image-20200530140108330.png

        

      新增灰度规则

        

      /resources/articles/spring/spring-cloud/apollo/image-20200530140307162.png

      /resources/articles/spring/spring-cloud/apollo/image-20200530140357612.png

        

      灰度发布

        

      /resources/articles/spring/spring-cloud/apollo/image-20200530140451746.png

        

      测试

        

      /resources/articles/spring/spring-cloud/apollo/image-20200530140610174.png

        

      放弃灰度

        

        确认放弃灰度以后会删除该灰度版本,并恢复为主版本的配置信息。

      /resources/articles/spring/spring-cloud/apollo/image-20200530140905522.png

        

      全量发布

        

        全量发布将会把灰度版本的配置合并到主分支,并发布。

      /resources/articles/spring/spring-cloud/apollo/image-20200530143144294.png

        

      发布历史

        

        可以通过发布历史来查看所有的发布记录,比如主版本发布,主版本回滚,灰度操作、灰度规则等等。

      /resources/articles/spring/spring-cloud/apollo/image-20200530143452975.png

        至此 Apollo 配置中心所有的知识点就讲解结束了。

      /resources/articles/articles_bottom/end02.gif

      本文采用 知识共享「署名-非商业性使用-禁止演绎 4.0 国际」许可协议

      大家可以通过 分类 查看更多关于 Spring Cloud 的文章。

        

      🤗 您的点赞转发是对我最大的支持。

      📢 扫码关注 哈喽沃德先生「文档 + 视频」每篇文章都配有专门视频讲解,学习更轻松噢 ~

      /resources/mrhelloworld/qrcode/OfficialAccounts500-500.gif

      「 感谢支持 」
       评论