JavaEE 企业级分布式高级架构师(十三)微服务框架 SpringCloud (H 版)(5)

分布式配置管理Spring Cloud Config

  • 集群中每一台主机的配置文件都是相同的,对配置文件的更新维护就成为了一个棘手的问题,Spring Cloud Config 是负责 Spring Cloud 中配置文件维护管理的配置中心。

概述

官网介绍

在这里插入图片描述

  • 原文】Spring Cloud Config provides server and client-side support for externalized configuration in a distributed system. With the Config Server you have a central place to manage external properties for applications across all environments.
  • 翻译】Spring Cloud Config 为分布式系统中的外部化配置提供服务器和客户端支持。使用 Config 服务器,可以在中心位置管理所有环境中应用程序的外部属性。

综合说明

  • Spring Cloud Config 就是对微服务的配置文件进行统一管理的。其工作原理是,我们首先需要将各个微服务公共的配置信息推送到 GitHub 远程版本库。然后我们再定义一个 Spring Cloud Config Server,其会连接上这个 GitHub 远程库。这样我们就可以定义 Config 版的 Eureka Server、提供者与消费者了,它们都将作为 Spring Cloud Config Client 出现,它们都会通过连接 Spring Cloud Config Server 连接上 GitHub 上的远程库,以读取到指定配置文件中的内容。

原理

Config Server 可以组装的最终配置文件格式有三种:yml、properties、json
在这里插入图片描述

github远程库设置

在github上创建远程库

  • 在 github 中创建一个 Spring Cloud Config 的远程版本库,git 库命名为 msc-config-center。

在这里插入图片描述

clone远程库到本地

  • 设置免密登录:在将远程库克隆到本地库之前需要先配置免密登录,否则会 Clone 会失败。
  • 本地生成密钥:由于生成的密钥默认是存放在本地版本库主机的当前用户主目录下的隐藏目录 .ssh 下的两个隐藏文件中,这两个文件分别是 id_sraid_rsa.pub。其中 id_sra 中存放的是私钥id_sra.pub 中存放的是公钥。所以在生成密钥前首先要看本地版本库主机的当前用户主目录, 确认是否存在公钥与私钥。若存在,则可直接使用。若没有,则需要生成。
  • 生成秘钥对命令:
ssh-keygen
  • 查看本地版本库主机的当前用户主目录,发现已经生成了.ssh 目录,查看该目录,其下也生成了 id_rsa 与 id_rsa.pub 文件,说明 SSH 密钥生成成功。

在这里插入图片描述

  • 远程设置公钥:打开公钥文件 id_rsa.pub 后复制里面内容。再打开 github 的 setting 设置页面,在相应位置(SSH and GPG keys)将复制的公钥粘贴进去。
  • 接下来就可以 clone 到本地了:
git clone git@github.com:shouwangyw/msc-config-center.git

将本地配置文件推送到远程库

  • 将 msc-config-center 仓库下载到本地后,在其根目录下编辑一个 application.yml 配置文件,该文件将用于后续的测试。为了方便,可以先在 Idea 中编写完毕,然后再复制到本地库。需要注意,该文件字符编码格式必须为 UTF-8,否则 push 到远程库后会出乱码问题。若不确定文件字符编码,可对文件进行另存为,然后选择字符编码。文件内容如下:
spring:
  profiles:
    active: dev

---
# 开发环境
spring:
  application:
    name: msc-config-dev
  profiles: dev

---
# 测试环境
spring:
  application:
    name: msc-config-test
  profiles: test
  • 将配置推送到远程git仓库:
$ git add *
$ git commit -m "init application.yml"
$ git push
  • 推送完毕后,刷新远程库页面,就可以看到该文件了。
  • 再分别创建三个配置文件:application-eureka-config.yml、application-provider-config.yml、application-consumer-config.yml,分别是 Eureka、Provider、Consumer 的配置文件。
  • application-eureka-config.yml
# 配置dev环境
spring:
  profiles: dev
  application:
    name: msc-eureka-server-config
server:
  port: 8400
eureka:
  instance:
    # 指定eureka主机
    hostname: eureka8400.com
  client:
    # 指定是否向注册中心注册自己
    register-with-eureka: false
    # 指定此客户端是否能够获取eureka注册信息
    fetch-registry: false
    # 暴露服务中心地址
    service-url:
      defaultZone: http://eureka8400.com:8400/eureka

---
# 配置test环境
spring:
  profiles: test
  application:
    name: msc-eureka-server-config
server:
  port: 8500
eureka:
  instance:
    # 指定eureka主机
    hostname: eureka8500.com
  client:
    # 指定是否向注册中心注册自己
    register-with-eureka: false
    # 指定此客户端是否能够获取eureka注册信息
    fetch-registry: false
    # 暴露服务中心地址
    service-url:
      defaultZone: http://eureka8500.com:8500/eureka
  • application-provider-config.yml
# 配置dev环境
server:
  port: 8190
spring:
  profiles: dev
  application:
    name: msc-provider-depart
  # 配置spring-data-jpa
  jpa:
    # 指定在Spring容器启动时是否自动建表,默认为false
    generate-ddl: true
    # 指定是否在控制台显示其执行的SQL语句,默认false
    show-sql: true
    # 指定应用重启时是否重新创建更新表
    hibernate:
      ddl-auto: none
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.254.128:3306/test?useUnicode=true&characterEncoding=utf8
    username: root
    password: 123456
eureka:
  client:
    service-url:
      defaultZone: http://eureka8400.com:8400/eureka
   
---
# 配置test环境
server:
  port: 8290
spring:
  profiles: test
  application:
    name: msc-provider-depart
  # 配置spring-data-jpa
  jpa:
    # 指定在Spring容器启动时是否自动建表,默认为false
    generate-ddl: true
    # 指定是否在控制台显示其执行的SQL语句,默认false
    show-sql: true
    # 指定应用重启时是否重新创建更新表
    hibernate:
      ddl-auto: none
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.254.128:3306/test?useUnicode=true&characterEncoding=utf8
    username: root
    password: 123456
eureka:
  client:
    service-url:
      defaultZone: http://eureka8500.com:8500/eureka
  • application-consumer-config.yml
# 配置dev环境
server:
  port: 8180
spring:
  profiles: dev
  application:
    name: msc-consumer-depart
eureka:
  client:
    service-url:
      defaultZone: http://eureka8400.com:8400/eureka
# 开启Feign对Hystrix的支持
feign:
  hystrix:
    enabled: true

---
# 配置test环境
server:
  port: 8280
spring:
  profiles: test
  application:
    name: msc-consumer-depart
eureka:
  client:
    service-url:
      defaultZone: http://eureka8500.com:8500/eureka
# 开启Feign对Hystrix的支持
feign:
  hystrix:
    enabled: true
  • 将以上三个创建好的配置文件推送到远端,并在 hosts文件添加配置:
127.0.0.1		eureka8400.com
127.0.0.1		eureka8500.com
127.0.0.1		configserver.com

搭建演示环境

创建配置文件工程 00-config-server-9999

  • 复制 00-eureka-server-8000 工程,重命名为 00-config-server-9999,并在此基础上进行修改。
  • 添加依赖:
<!-- config的依赖 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-config-server</artifactId>
</dependency>
  • 启动类:使用 @EnableConfigServer 注解开启 ConfigServer 服务功能
@EnableConfigServer // 开启ConfigServer服务功能
@SpringBootApplication
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}
  • 修改配置文件 application.yml:
server:
  port: 9999
# 指定当前工程所关联的 git 远程库地址
spring:
  cloud:
    config:
      server:
        git:
#          uri: git@github.com:shouwangyw/ywmsc-config-center.git
          # macbook上配置为https方式
          uri: https://github.com/shouwangyw/ywmsc-config-center.git
          timeout: 5	# 获取到远程git库连接的超时时限,默认为5秒
          default-label: master	# 指定要操作的远程git库的分支,默认master
          # 指定拉取下来的git库位置
          basedir: /Volumes/D/git/ywmsc-config-center
  • 启动 ConfigServer 服务,并测试一下:http://configserver.com:9999/application-dev.json

在这里插入图片描述

创建config版的EurekaServer工程 00-eureka-config-server

  • 复制 00-eureka-server-8000 工程,并重命名为 06-config-eurekaserver。
  • 添加config客户端依赖:
<!-- spring cloud config 客户端依赖 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
  • 配置文件修改:将原来的 application.yml 重命名为 bootstrap.yml,配置修改成下面的
spring:
  cloud:
    config:
      # 指定ConfigServer的地址
      uri: http://configserver.com:9999
      # config集群地址
      # uri: http://configserver.com:9999,http://configserver.com:8888
      # 指定要拉取配置的分库
      label: main
      # 指定要从远程读取的配置文件名称【无需扩展名】
      name: application-eureka-config
      # 环境选择
      profile: dev
  • 启动 EurekaServer 服务,能正常启动,端口为远程配置文件设置的8400端口,访问地址http://eureka8400.com:8400/测试一下也是OK的。

创建config版的提供者工程 06-provider-config

  • 复制 04-provider-8090 工程,重命名为 06-provider-config,在此基础上修改。
  • 添加依赖:与前面 Eureka 的一样,spring cloud config 客户端依赖。
  • 配置文件修改:将原来的 application.yml 重命名为 bootstrap.yml,配置也和 Eureka 的差不多

在这里插入图片描述

  • 启动工程没有报错,测试接口:http://localhost:8190/provider/depart/get/1,也能正常。

创建config版的消费者工程 06-consumer-config

  • 复制 04-consumer-hystrix-8080 工程,重命名为 06-consumer-config,在此基础上进行修改。和 06-provider-config 工程一样,添加 spring cloud config 的客户端依赖,并修改配置文件。

在这里插入图片描述

  • 启动工程没有报错,测试接口:http://localhost:8180/consumer/depart/get/1,也能正常。

配置自动更新

Webhooks

  • GitHub 中提供了 Webhooks 功能来确保远程库中的配置文件更新后,客户端中的配置信息也可以实时更新。具体实现方式可参考如下一篇博文:https://blog.csdn.net/qq_32423845/article/details/79579341
  • 这种方式存在很大的弊端,并不适合生产环境下的使用,而 Spring Cloud Bus 消息总线系统解决了这些问题。所以,生产环境下一般使用的是 Spring Cloud Bus 完成配置文件的自动更新。

webhooks 存在的弊端?

  • 每个 config client 都需要在 git 远程库中注册,若 config client 数量发生变化,则需要修改 git 远程库。
  • 每个 config client 若要在不重启的情况下更新配置,则都需要提交一个 actuator 的 post 请求。这样的话,若存在多个 config client 需要更新,则需要提交多个这样的 post 请求。

Spring Cloud Bus概述

官方简介

在这里插入图片描述

  • 翻译】用于将服务和服务实例与分布式消息系统链接在一起的事件总线。在集群中传播状态更改很有用(例如配置更改事件)。
工作原理

在这里插入图片描述

配置自动更新原理

在这里插入图片描述

  • 向任意一个 Config Client 提交一个 POST:bus-refresh 请求,则该 Client 就会把 Config Server 上的更新信息加载下来,同时该 Client 还会把该更新信息通过消息总线系统通知到其它的 Config Client 上,这样这些接收到通知的 Config Client 就会去 Config Server 上把更新信息加载下来。

功能演示

修改配置文件
  • 分别在 application-consumer-config.yml、application-provider-config.yml 两个配置文件中增加自定义属性:
# application-consumer-config.yml 自定义属性
prefix: begin++
# application-provider-config.yml 自定义属性
suffix: ++end
修改消费者和提供者工程
  • Consumer 工程:
public class DepartController {
    @Autowired
    private DepartService departService;

    @Value("${prefix}")
    private String prefix;
	
	@GetMapping("/get/{id}")
    public Depart getHandle(@PathVariable("id") int id) {
        Depart depart = departService.getDepartById(id);
        return depart.setName(prefix + depart.getName());
    }
}
  • Provider 工程:
@Service
public class DepartServiceImpl implements DepartService {
    @Autowired
    private DepartRepository repository;
    @Value("${server.port}")
    private int port;
    @Value("${suffix}")
    private String suffix;
    // ...略

    @Override
    public Depart getDepartById(int id) {
        try {
            TimeUnit.SECONDS.sleep(id);
        } catch (Exception ignore){ }
        // repository.getOne()中指定的id若不存在,则会抛出异常,因此这里要先判断是否存在
        if (repository.existsById(id)) {
            Depart depart = repository.getOne(id);
            depart.setName(rename(depart.getName()));
            return depart;
        }
        return new Depart().setName(port + " No this depart");
    }
    private String rename(String name) {
        return name + suffix;
    }
}
  • 然后分别启动消费者和提供者工程,并进行接口 http://localhost:8180/consumer/depart/get/1 测试。

在这里插入图片描述

  • 返回结果分别拼接上了提供者和消费者的自定义属性值,但是这种方式没办法进行动态的更新。
Bus实现配置动态更新
  • 添加依赖:在 Provider 和 Consumer 中都添加 bus 的依赖
<!-- bus-kafka依赖 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-bus-kafka</artifactId>
</dependency>
  • 修改配置文件:配置kafka集群地址,开启 bus-refresh 监控终端
spring:
  cloud:
    config:
      # 指定ConfigServer的地址
      uri: http://configserver.com:9999
      # 指定要拉取配置的分库
      label: main
      # 指定要从远程读取的配置文件名称【无需扩展名】
      name: application-consumer-config
      # 环境选择
      profile: dev
  # 配置kafka集群地址
  kafka:
    bootstrap-servers: 192.168.254.128:9092,192.168.254.130:9092,192.168.254.132:9092
# 开启 bus-refresh 监控终端
management:
  endpoints:
    web:
      exposure:
        include: bus-refresh
  • 接口实现类上加注解 @RefreshScope

在这里插入图片描述

  • 重启 Provider 和 Consumer 工程,测试接口:http://localhost:8180/consumer/depart/get/1。修改 Provider 和 Consumer 工程的远程库中的配置文件,此时刷新接口,修改的配置还不会生效,要使得修改的配置生效,还需要提交一个 POST:bus-refresh 请求:
# 任意一个 Config Client 提交这个POST请求都可以
http://localhost:8180/actuator/bus-refresh
查看Zookeeper中的信息

在这里插入图片描述

  • 查看 Zookeeper 中的信息,Bus 的实现利用了 kafka,主题为 springCloudBus

调用链跟踪Spring Cloud Sleuth+zipkin

  • 业界的调用链跟踪产品:
    • Google—Dapper
    • 淘宝-鹰眼-Eagleeye
    • 京东-Hydra
    • 大众点评-cat
    • 新浪-watchman
    • 唯品会-microscope
    • Twitter-Zipkin

Sleuth简介

  • 打开官网就可以看到对 Sleuth 的一个简单功能介绍。

在这里插入图片描述

  • 翻译】(Spring Cloud Sleuth 可以实现)针对 Spring Cloud 应用程序的分布式跟踪,兼容 Zipkin、HTrace 和基于日志的(如:Elk)跟踪。

Sleuth基本理论

  • Spring Cloud Sleuth 的官方文档中可以查看到服务跟踪的基本理论。

三大概念

  • 服务跟踪理论中存在有跟踪单元的概念,而跟踪单元中涉及三个重要概念:tracespan、与 annotation

在这里插入图片描述

trace与span
  • trace:跟踪单元是从客户端所发起的请求抵达被跟踪系统的边界开始,到被跟踪系统向客户返回响应为止的过程,这个过程称为一个 trace。
  • span:每个 trace 中会调用若干个服务,为了记录调用了哪些服务,以及每次调用所消耗的时间等信息,在每次调用服务时,埋入一个调用记录,这样一个调用记录称为一个span。
  • 关系:一个 trace 由若干个有序的 span 组成。
  • Spring Cloud Sleuth 为服务之间调用提供链路追踪功能。为了唯一的标识 trace 与 span,系统为每个 trace 与 span 都指定了一个 64 位长度的数字作为 ID,即 traceID 与 spanID。
annotation
  • 用于及时记录事件的实体,表示一个事件发生的时间点。这些实体本身仅仅是为了原理叙述的方便,对于 Spring Cloud Sleuth 本身并没有什么必要性。这样的实体有多个,常用的有四个:
    • cs:Client Send,客户端发送请求的时间点
    • sr:Server Receive,服务端接收到请求的时间点
    • ss:Server Send,服务端发送响应的时间点
    • cr:Client Receive,客户端接收响应的时间点

Sleuth的日志采样

日志生成

只要在工程中添加了 Spring Cloud Sleuth 依赖, 那么工程在启动与运行过程中就会自动生成很多的日志。Sleuth 会为日志信息打上收集标记,需要收集的设置为 true,不需要的设置为 false。这个标记可以通过在代码中添加自己的日志信息看到。

日志采样率
  • Sleuth 对于这些日志支持抽样收集,即并不是所有日志都会上传到日志收集服务器,日志收集标记就起这个作用。默认的采样比例为:0.1,即 10%。在配置文件中可以修改该值。若设置为 1 则表示全部采集,即 100%。
  • Sleuth 默认采用的是水塘抽样算法。

“跟踪日志”的生产者Sleuth

创建提供者工程 07-provider-sleuth-8090

  • 复制 03-provider-8090 工程,并重命名为 07-provider-sleuth-8090,在此基础上修改。
  • 添加 sleuth 依赖
<!-- sleuth依赖 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
  • 在控制器层接口和业务层添加一些日志,并将配置文件中的日志配置注释掉,修改完后启动提供者工程。

在这里插入图片描述

创建消费者工程 07-consumer-sleuth-8080

  • 复制 03-consumer-feign-8080 工程,并重命名为 07-consumer-sleuth-8080,在此基础上修改。添加 sleuth 依赖,在控制器层接口和业务层添加一些日志,并将配置文件中的日志配置注释掉,修改完后启动消费者工程。

在这里插入图片描述

  • 测试接口:http://localhost:8080/consumer/depart/get/1

zipkin工作过程

zipkin简介

  • zipkin 是 Twitter 开发的一个分布式系统 APM(Application Performance Management,应用性能管理)工具,其是基于 Google Dapper 实现的,用于完成日志的聚合。其与 Sleuth 联用,可以为用户提供调用链路监控可视化 UI 界面。

zipkin系统结构

服务器组成

在这里插入图片描述

zipkin 服务器主要由 4 个核心组件构成:

  • Collector收集组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为 Zipkin 内部处理的 Span 格式,以支持后续的存储、分析、展示等功能。
  • Storage存储组件,它主要用于处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中,也可以修改存储策略,例如,将跟踪信息存储到数据库中。
  • API外部访问接口组件,外部系统通过这里的API可以实现对系统的监控。
  • UI用于操作界面组件,基于 API 组件实现的上层应用。通过 UI 组件用户可以方便而有直观地查询和分析跟踪信息。
日志发送方式
  • 在 Spring Cloud Sleuth + zipkin 系统中,客户端中一旦发生服务间的调用,就会被配置在微服务中的 Sleuth 的监听器监听,然后生成相应的 Trace 和 Span 信息,并发送给 zipkin 服务端。发送的方式主要有两种:一种是通过 via HTTP 报文的方式也可以通过 Kafka、RabbitMQ 发送

zipkin服务端搭建

启动zipkin服务器

# 下载
curl -sSL https://zipkin.io/quickstart.sh | bash -s
# 启动
java -jar zipkin.jar

访问zipkin服务器

  • 地址:http://localhost:9411/zipkin

在这里插入图片描述

sleuth整合zipkin——via HTTP方式

在这里插入图片描述

修改提供者、消费者工程

  • 添加依赖:删除原来的 sleuth 依赖,导入 zipkin 依赖,因为 spring-cloud-starter-zipkin 中已经包含了 sleuth 的依赖。
<!-- zipkin客户端依赖,其包含了sleuth依赖 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
  • 修改配置文件:在 spring 属性下注册 zipkin 服务器地址,并设置采样比例。
spring:
  # 指定zipkin服务地址
  zipkin:
    base-url: http://localhost:9411/
  # 设置采样比例为1.0,即全部都需要,默认为0.1
  sleuth:
    sampler:
      probability: 1.0

重启运行

  • 重启提供者和消费者工程,并在浏览器多次访问接口:http://localhost:8080/consumer/depart/get/1,再打开 zipkin 的UI界面查看

在这里插入图片描述

sleuth+kafka+zipkin整合

在这里插入图片描述

修改提供者、消费者工程

  • 在前面的工程基础上再添加 kafka 依赖
<!-- kafka依赖 -->
<dependency>
  <groupId>org.springframework.kafka</groupId>
  <artifactId>spring-kafka</artifactId>
</dependency>
  • 修改配置文件:
spring:
  zipkin:
#    base-url: http://localhost:9411/
    sender:
      type: kafka
  kafka:
    bootstrap-servers: 192.168.254.128:9092,192.168.254.130:9092,192.168.254.132:9092
  # 设置采样比例为1.0,即全部都需要,默认为0.1
  sleuth:
    sampler:
      probability: 1.0

重启运行

  • zipkin的启动方式需要修改:
java -DKAFKA_BOOTSTRAP_SERVERS=192.168.254.128:9092 -jar zipkin.jar
  • 重启提供者和消费者工程,并在浏览器多次访问接口:http://localhost:8080/consumer/depart/get/1,再打开 zipkin 的UI界面查看。发现同样可以实现前面的功能。

在这里插入图片描述

  • 查看Zookeeper:zipkin 使用的 kafka 主题是 zipkin

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

讲文明的喜羊羊拒绝pua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值