SpringCloud - Spring Cloud 之 Apollo Config携程阿波罗配置中心(二十一)

Posted MinggeQingchun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud - Spring Cloud 之 Apollo Config携程阿波罗配置中心(二十一)相关的知识,希望对你有一定的参考价值。

由于Spring Cloud自带的Config 需要配合 Bus 使用,且不能实时刷新,因此市面上出现了很多开元的配置中心

市面上开源的配置中心

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

diamond : 淘宝开源的持久配置中心,支持各种持久信息(比如各种规则,数据库配置等)的发布和订阅;(更新稍微落后一点)

XDiamond:全局配置中心,存储应用的配置项,解决配置混乱分散的问题,名字来源于淘宝的开源项目diamond,前面加上一个字母X以示区别。

Qconf: 奇虎360内部分布式配置管理工具,用来替代传统的配置文件,使得配置信息和程序代码分离,同时配置变化能够实时同步到客户端,而且保证用户高效读取配置,这使的工程师从琐碎的配置修改、代码提交、配置上线流程中解放出来,极大地简化了配置管理工作;

Disconf:百度的分布式配置管理平台,专注于各种分布式系统配置管理的通用组件和通用平台, 提供统一的配置管理服务

Apollo(GitHub - apolloconfig/apollo: Apollo is a reliable configuration management system suitable for microservice configuration management scenarios.)是一个配置中心,支持从应用、环境、集群维度去管理配置,也支持从公共,私有维度去管理配置。 满足了大部分的配置场景。 

Apollo官网Apollo

以下是 Spring Cloud Config 和 Apollo对比

一、部署Apollo运行环境

官网 Quick Start 文档Apollo

1、环境准备

1、Java

  • Apollo服务端:1.8+
  • Apollo客户端:1.8+
    • 如需运行在 Java 1.7 运行时环境,请使用 1.x 版本的 apollo 客户端,如 1.9.1

在配置好后,可以通过如下命令检查:

java -version

样例输出:

java version "1.8.0_74"
Java(TM) SE Runtime Environment (build 1.8.0_74-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)

Windows用户请确保JAVA_HOME环境变量已经设置 

2、mysql

  • 版本要求:5.6.5+

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

连接上MySQL后,可以通过如下命令检查:

SHOW VARIABLES WHERE Variable_name = 'version';
Variable_nameValue
version5.7.11

2、下载Quick Start安装包

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

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

  1. 从GitHub下载
  2. 从百度网盘下载
    • 通过网盘链接下载,提取码: 9wwe
    • 下载到本地后,在本地解压apollo-quick-start.zip
  3. 为啥安装包要58M这么大?
    • 因为这是一个可以自启动的jar包,里面包含了所有依赖jar包以及一个内置的tomcat容器

手动打包 Quick Start安装包

Quick Start只针对本地测试使用,所以一般用户不需要自己下载源码打包,只需要下载已经打好的包即可。不过也有部分用户希望在修改代码后重新打包,那么可以参考如下步骤:

  1. 修改apollo-configservice, apollo-adminservice和apollo-portal的pom.xml,注释掉spring-boot-maven-plugin和maven-assembly-plugin
  2. 在根目录下执行mvn clean package -pl apollo-assembly -am -DskipTests=true
  3. 复制apollo-assembly/target下的jar包,rename为apollo-all-in-one.jar

二、安装步骤

1、创建数据库

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

导入成功后,可以通过执行如下sql语句来验证:

select `Id`, `AppId`, `Name` from ApolloPortalDB.App;

select `NamespaceId`, `Key`, `Value`, `Comment` from ApolloConfigDB.Item;

2、配置数据库连接信息 

#!/bin/bash

# apollo config db info
apollo_config_db_url=jdbc:mysql://localhost:3306/ApolloConfigDB?useSSL=false&&characterEncoding=utf8&&serverTimezone=Asia/Shanghai
apollo_config_db_username=root
apollo_config_db_password=admin123456

# apollo portal db info
apollo_portal_db_url=jdbc:mysql://localhost:3306/ApolloPortalDB?useSSL=false&&characterEncoding=utf8&&serverTimezone=Asia/Shanghai
apollo_portal_db_username=root
apollo_portal_db_password=admin123456

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

这里可能会出现一个问题

demo.sh 启动 报错

==== starting service ====
Service logging file is ./service/apollo-service.log
Started [3120]
Waiting for config service startup........................
Config service failed to start in 120 seconds! Please check ./service/apollo-service.log for more information.

这里有两种解决办法

1、mysql禁用SSL

(1)由于我的mysql是5.7之后的,后面得加useSSL=false,禁用SSL(安全套接字协议)

(2)属性之间的连接得用&&,用&还是启动失败

#!/bin/bash
 
# apollo config db info
apollo_config_db_url=jdbc:mysql://localhost:3306/ApolloConfigDB?useSSL=false&&characterEncoding=utf8&&serverTimezone=Asia/Shanghai
apollo_config_db_username=root
apollo_config_db_password=admin123456
 
# apollo portal db info
apollo_portal_db_url=jdbc:mysql://localhost:3306/ApolloPortalDB?useSSL=false&&characterEncoding=utf8&&serverTimezone=Asia/Shanghai
apollo_portal_db_username=root
apollo_portal_db_password=admin123456

2、 mysql修改URL

刚开始配置数据库连接url是 localhost,一直报错连接不上,回想了一下,博主是将Apollo配置在Linux端,因此将数据库 连接url换成 Linux上的 IP地址,并且启动 mysql服务

#!/bin/bash
 
# apollo config db info
apollo_config_db_url=jdbc:mysql://192.168.133.129:3306/ApolloConfigDB?useSSL=false&&characterEncoding=utf8&&serverTimezone=Asia/Shanghai
apollo_config_db_username=root
apollo_config_db_password=admin123456
 
# apollo portal db info
apollo_portal_db_url=jdbc:mysql://192.168.133.129:3306/ApolloPortalDB?useSSL=false&&characterEncoding=utf8&&serverTimezone=Asia/Shanghai
apollo_portal_db_username=root
apollo_portal_db_password=admin123456

3、启动Apollo配置中心

注:

启动之前确保 mysql服务开启,且数据库 ApolloConfigDB 和 ApolloPortalDB 已经创建好(如果是Docker启动的 MySQL,要挂载MySQL,以免删除或者停止mysql容器后能保留数据库文件,不至于导致数据库丢失)

执行启动脚本

./demo.sh start

启动成功之后,会输出如下信息

注:

./demo.sh start   (里面会启动三个服务

Config-service  8080端口

Admin-service  8090端口

Portal管控台  8070端口,启动会比较慢)

./demo.sh start
==== starting service ====
Service logging file is ./service/apollo-service.log
Application is running as root (UID 0). This is considered insecure.
Started [10272]
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
Application is running as root (UID 0). This is considered insecure.
Started [10474]
Waiting for portal startup....
Portal started. You can visit http://localhost:8070 now!

启动成功后,访问:http://ip:8070 登录账号默认是: apollo/admin 

三、创建应用

1、点击创建应用

2、填写 APPId,应用名称等 

3、点击“提交”,创建成功,首次会警告,点击“发布”即可 

4、将项目中 application.properties 配置文件中的配置信息复制到 “文本”处,保存,点击发布 

5、可以在表格中看到各项参数配置 

四、Apollo应用

1、创建应用 springcloud-12-service-apollo-config-provider

2、添加 Apollo依赖

<!-- 携程apollo-client -->
        <dependency>
            <groupId>com.ctrip.framework.apollo</groupId>
            <artifactId>apollo-client</artifactId>
            <version>1.7.0</version>
        </dependency>
<!--继承统一的父项目-->
    <parent>
        <groupId>com.company</groupId>
        <artifactId>springcloud-demo</artifactId>
        <version>1.0.0</version>
    </parent>

    <groupId>com.company</groupId>
    <artifactId>springcloud-12-service-apollo-config-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <name>springcloud-12-service-apollo-config-provider</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--spring web 起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- mybatis-spring-boot-starter
            !!!需要添加版本号,不然报错
            [ERROR] 'dependencies.dependency.version' for org.mybatis.spring.boot:mybatis-spring-boot-starter:jar is missing. @ line 32, column 21
         -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <!-- MySQL的jdbc驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--依赖统一的springcloud-service-commons项目
            !!!需要添加版本号,不然报错
            [ERROR] 'dependencies.dependency.version' for com.company:springcloud-2-service-common:jar is missing. @ line 44, column 21
        -->
        <dependency>
            <groupId>com.company</groupId>
            <artifactId>springcloud-2-service-common</artifactId>
            <version>1.0.0</version>
        </dependency>

        <!--spring-cloud-starter-netflix-eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!-- 携程apollo-client -->
        <dependency>
            <groupId>com.ctrip.framework.apollo</groupId>
            <artifactId>apollo-client</artifactId>
            <version>1.7.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3、在 bootstrap.properties 或者 application.properties 中配置

####====使用携程Apollo配置中心---start====#####
#appId
app.id=springcloud-12-service-apollo-config-provider
#config services url
apollo.meta=http://192.168.133.129:8080
####====使用携程Apollo配置中心---end====#####

我们的应用程序也就是Apollo客户端依赖于AppId,Apollo Meta Server等环境信息来工作,需要做如下配置:

AppId:AppId是应用的身份信息,是从服务端获取配置的一个重要信息;

(1)Spring Boot application.properties

Apollo 支持通过Spring Boot的application.properties或bootstrap.properties文件配置:

app.id=YOUR-APP-ID

(2)app.properties

在项目的classpath:/META-INF/app.properties文件存在,并且其中内容配置:

app.id=YOUR-APP-ID

Apollo Meta Server:元数据服务器;

Apollo可以在Spring Boot的application.properties或bootstrap.properties中指定apollo.meta=http://config-service-url

通过app.properties配置文件在classpath:/META-INF/app.properties指定apollo.meta=http://config-service-url

4、在springboot启动类上添加注解 @EnableApolloConfig 开启apollo配置支持

@EnableApolloConfig //开启apollo配置支持
@SpringBootApplication(scanBasePackages="com.company")
public class ServiceApolloConfig12ProviderApplication 
    public static void main(String[] args) 
        SpringApplication.run(ServiceApolloConfig12ProviderApplication.class, args);
    

5、启动项目测试

Apollo客户端会把从服务端获取到的配置在本地文件系统缓存一份,用于在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置,不影响应用正常运行;

本地缓存路径默认位于以下路径,所以请确保/opt/data或C:\\opt\\data\\目录存在,且应用有读写权限;

Mac/Linux: /opt/data/appId/config-cache

Windows: C:\\opt\\data\\appId\\config-cache

appId+cluster+namespace.properties

五、Apollo客户端的实现原理

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

(通过Http Long Polling实现)

2、客户端还会定时从Apollo配置中心服务端拉取应用的最新配置,这是一个fallback机制,为了防止推送机制失效导致配置不更新;

3、客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified;

定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟;

4、客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中;

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

在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置;

5、应用程序可以从Apollo客户端获取最新的配置、订阅配置更新通知;

六、Apollo阿波罗配置中心设计

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进程中;

七、Apollo模块

1、Config Service

提供配置获取接口

提供配置更新推送接口(基于Http long polling)

服务端使用Spring DeferredResult实现异步化,从而大大增加长连接数量

目前使用的tomcat embed默认配置是最多10000个连接(可以调整),使用了4C8G的虚拟机实测可以支撑10000个连接,所以满足需求(一个应用实例只会发起一个长连接)。

接口服务对象为Apollo客户端

2、Admin Service

提供配置管理接口

提供配置修改、发布等接口

接口服务对象为Portal

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一致

4、Eureka

基于Eureka和Spring Cloud Netflix提供服务注册和发现

Config Service和Admin Service会向Eureka注册服务,并保持心跳

为了简单起见,目前Eureka在部署时和Config Service是在一个JVM进程中的(通过Spring Cloud Netflix)

5、Portal

提供Web界面供用户管理配置

通过Meta Server获取Admin Service服务列表(IP+Port),通过IP+Port访问服务

在Portal侧做load balance、错误重试

6、Client

Apollo提供的客户端程序,为应用提供配置获取、实时更新等功能

通过Meta Server获取Config Service服务列表(IP+Port),通过IP+Port访问服务

在Client侧做load balance、错误重试;

以上是关于SpringCloud - Spring Cloud 之 Apollo Config携程阿波罗配置中心(二十一)的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud总结29.Zuul的FallBack回退机制

基于consul的服务注册(含踩坑过程)

Oauth2.0 整合springCloud的Zuul 解决关键BUG 报错信息:Principal must not be null

Spring Cloud Alibaba - 02 SpringCloud SpringCloud Alibaba SpringBoot的生产版本选择

Spring Cloud

spring cloud 服务注册、发现了解