SpringCloud学习笔记(七)----配置中心Config、消息总线Bus

SpringCloud config分布式配置中心

概述

分布式系统面临的配置问题:

微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。

通俗来说,每个微服务都需要一个配置文件,如果有几个微服务都需要连接数据库,那么就需要配4次数据库相关配置,并且当数据库发生改动,那么需要同时修改4个微服务的配置文件才可以。

所以有了SpringCloud Config配置中心来统一管理微服务中相同配置文件。

config是什么?

SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。
SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第1张图片
SpringCloud Config分为服务端和客户端两部分。

服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。

客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息配置服务器,默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容。

Config 能干嘛?

  1. 集中管理配置文件
  2. 不同环境不同配置,动态化的配置更新,分环境部署比如dev/test/prod/beta/release
  3. 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息。
  4. 当配置发生变动时,服务不再需要重启即可感知到配置的变化并应用新的配置。
  5. 将配置信息以REST接口的形式暴露

SpringCloud Config默认使用Git来存储配置文件(也有其它方式,比如支持svn和本地文件,但最推荐的还是Git,而且使用的是http/https访问的形式)

Config服务端配置与测试

使用Github作为配置中心的仓库

初始化git环境

1.在Github上新建一个名为springcloud-config的新Repository

2.获取新建的git地址
[email protected]:xiaoxinxin718/springcloud-config.git

3.本地硬盘上新建git仓库并clone
git clone 上面获取的git地址

进行clone的时候,报如下错误:
SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第2张图片
本地git bash 使用git clone [email protected]:***.git方式下载github代码至本地时需要依赖ssh key,遇到权限不足问题时一般都是SSH key失效或者SSH key不存在,重新创建SSH key一般就可以解决问题; 可以参照下面这篇博客
https://blog.csdn.net/sxg0205/article/details/81412921

解决之后,在进行clone,本地仓库已有从GitHub上下载下来的文件。
SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第3张图片
SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第4张图片

新建config模块

1.新建Module模块cloud-config-center-3344它为Cloud的配置中心模块cloudConfig Center
2.POM.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${
     project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

3.application.yml

server:
  port: 3344
spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          uri:  填写你自己的github路径
          search-paths:
            - springcloud-config
      label: master
eureka:
  client:
    service-url:
      defaultZone:  http://localhost:7001/eureka

4.主启动类

@SpringBootApplication
@EnableConfigServer
public class ConfigCenterMain3344 {
     
    public static void main(String[] args) {
     
        SpringApplication.run(ConfigCenterMain3344 .class,args);
    }
}

测试通过Config微服务是否可以从Github上获取配置内容。

访问http://localhost:3344/master/config-dev.yml,发现报如下错误:
SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第5张图片
上网百度了一大堆解决办法,经过一一尝试,将配置文件修改如下:

server:
  port: 3344
spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          uri: https://github.com/xiaoxinxin718/springcloud-config.git
          #git@github.com:xiaoxinxin718/springcloud-config.git
          search-paths:
            - springcloud-config
          username: github账号
          password: github密码
          skip-ssl-validation: true
        default-label: master
eureka:
  client:
    service-url:
      defaultZone:  http://localhost:7001/eureka

这样配置解决上面哪个错误,但是又出现了一个新的错误。
SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第6张图片
默认的label为master
Github现在master改为main, 修改 default-label 属性, 否则读不到

default-label: main

在测试,已成功实现用SpringCloud config 通过GitHub获取配置信息。

SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第7张图片
SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第8张图片

配置读取规则

SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第9张图片

1./{label}/{application}-{profile}.yml(最推荐使用这种方式)
label:分支(brance) name:服务名 profiles:环境(dev/test/prod)

main分支

  • http://localhost:3344/main/config-dev.yml
  • http://localhost:3344/main/config-test.yml
  • http://localhost:3344/main/config-prod.yml

dev分支

  • http://localhost:3344/dev/config-dev.yml
  • http://localhost:3344/dev/config-test.yml
  • http://localhost:3344/dev/config-prod.yml

2./{application}-{profile}.yml

  • http://localhost:3344/config-dev.yml
  • http://localhost:3344/config-test.yml
  • http://localhost:3344/config-prod.yml
  • http://localhost:3344/config-xxxx.yml(不存在的配置)
  • 如果访问不存在的配置,会返回一个空{},并不会报错。
  • 默认读取main分支,因为我们配置文件配置了。

3./{application}-{profile}[/{label}]

  • http://localhost:3344/config/dev/master
  • http://localhost:3344/config/test/master
  • http://localhost:3344/config/prod/master
  • 这个方法读取的配置是JSON格式的。

Config客户端配置与测试

1.新建cloud-config-client-3355
2.POM.xml

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${
     project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

3.bootstrap.yml

这个配置文件的作用是,先到配置中心加载配置,然后加载到application.yml中。

application.yml是用户级的资源配置项
bootstrap.yml是系统级的,优先级更加高。

SpringCloud 会创建一个"Bootstrap Context",作为Spring应用的"Application Context"的父上下文。初始化的时候,“Bootstrap Context"负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的"Environment”。

"Bootstrap"属性有高优先级,默认情况下,它们不会被本地配置覆盖。“Bootstrap context"和"Application Context"有着不同的约定,所以新增了一个"bootstrap.yml"文件,保证"Bootstrap Context” 和"Application Context"配置的分离。

要将Client模块下的application.yml文件改为bootstrap.yml,这是很关键的。
因为bootstrap.yml是比application.yml先加载的。bootstarp.yml优先级高于application.yml。

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:

      #这四个整合在一起的意思是:客户端会读取http://localhost3344/main/config-dev.yml上面的配置文件
      label: main #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称,
      uri: http://localhost:3344 #配置中心地址k
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka

4.主启动类

@SpringBootApplication
@EnableEurekaClient
public class ConfigClientMain3355 {
     
    public static void main(String[] args) {
     
        SpringApplication.run( ConfigClientMain3355.class,args);
    }
}

5.controller类
前面所提到的,以rest风格将配置对外暴露。

@RestController
public class ConfigClientController {
     

    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo(){
     
        return configInfo;
    }
}

6.测试:
启动3344、3355,访问 http://localhost:3355/configInfo。成功实现了客户端3355访问SpringCloud Config3344通过GitHub获取配置信息

SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第10张图片
7.问题:
上面3355确认获取到了配置文件,但是如果此时配置文件修改了,3355是获取不到的,3344可以实时获取到最新配置文件,除非3355重启服务。

Config客户端之动态刷新

1.修改3355,添加一个pom依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2.修改配置文件,添加一个配置:
暴露监控端口。

management:
  endpoints:
    web:
      exposure:
        include: "*"

3.修改controller,添加@RefreshScope

@RestController
@RefreshScope
public class ConfigClientController {
     

    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo(){
     
        return configInfo;
    }
}

4.重启3355
此时3355还不可以动态获取。 还需要外部发生post请求通知3355。
SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第11张图片
此时在刷新3355,发现可以获取到最新的配置文件了,这就实现了动态获取配置文件,因为3355并没有重启。

具体流程就是:

  • 启动好服务之后
  • 运维人员,修改了配置文件,然后发送一个post请求通知3355
  • 3355就可以获取最新配置文件。

问题:
如果有多个客户端怎么办(3355,3356,3357…),虽然可以使用shell脚本,循环刷新。

但是可不可以使用广播,一次通知?
我们可以使用SpringCloud Bus配合SpringCloud Config实现。

消息总线SpringCloud Bus

概述

Spring Cloud Bus配合Spring Cloud Config 使用可以实现配置的动态刷新。
SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第12张图片
Spring Cloud Bus 能管理和传播分布式系统间的消息,就像一个分布式执行器,可用于广播状态更改、事件推送等,也可以当作微服务间的通信通道。

SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第13张图片
注意,这里两张图片,就代表两种广播方式:

  • 图1:它是Bus直接通知给其中一个客户端,由这个客户端开始蔓延,传播给其他所有客户端。
  • 图2:它是通知给配置中心的服务端,由服务端广播给所有客户端。

为什么被称为总线

在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统中所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线。在总线上的各个实例,都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息。

基本原理:
ConfigClient实例都监听MQ中同一个topic(默认是springCloudBus)。当一个服务刷新数据的时候,它会把这个信息放入到Topic中,这样其它监听同一Topic的服务就能得到通知,然后去更新自身的配置。

简单来说:
就是通过消息队列达到广播的效果,我们要广播每个消息时,主要放到某个topic中,所有监听的节点都可以获取到。

RabbitMQ环境配置

安装过程可以看我以前写的在Linux下安装RabbitMQ博客。
安装RabbitMQ

SpringCloud Bus动态刷新全局广播

为了演示广播效果,根据3355在创建一个cloud-config-client-3366模块。

Bus广播有两种形式:

  • 利用消息总线触发一个客户端/bus/refresh,而刷新所有客户端的配置。
  • 利用消息总线触发一个服务端ConfigServer的/bus/refresh端点,而刷新所有客户端的配置(更加推荐)

方法一有如下缺点:

  • 打破了微服务的职责单一性,因为微服务本身是业务模块,它本不应该承担配置刷新职责
  • 破坏了微服务各节点的对等性
  • 有一定的局限性。例如,微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动刷新,那就会增加更多的修改

所以选择方法二的架构。

给cloud-config-center-3344配置中心服务端添加消息总线支持

1.在POM.xml添加如下依赖

<!--添加消息总线RabbitMQ支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2.修改配置文件

server:
  port: 3344
spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          uri: https://github.com/xiaoxinxin718/springcloud-config.git
          #git@github.com:xiaoxinxin718/springcloud-config.git
          search-paths:
            - springcloud-config
          username: xiaoxinxin718
          password: 1424025155abc
          skip-ssl-validation: true
        default-label: main
  #rabbitmq相关配置  15672是web管理界面的端口,5672是MQ访问的端口
  rabbitmq:
    host: 172.16.114.135
    port: 5672
    username: guest
    password: guest


eureka:
  client:
    service-url:
      defaultZone:  http://localhost:7001/eureka

#rabbitmq相关配置,暴露bus刷新配置的端点
management:
  endpoints: #暴露bus刷新配置的端点
    web:
      exposure:
        include: 'bus-refresh'

给cloud-config-center-3355客户端添加消息总线支持

1.在POM.xml添加如下依赖

<!--添加消息总线RabbitMQ支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2.修改配置文件

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:

      #这四个整合在一起的意思是:客户端会读取http://localhost3344/main/config-dev.yml上面的配置文件
      label: main #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称,
      uri: http://localhost:3344 #配置中心地址k
  #rabbitmq相关配置  15672是web管理界面的端口,5672是MQ访问的端口
  rabbitmq:
    host: 172.16.114.135
    port: 5672
    username: guest
    password: guest
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka


management:
  endpoints:
    web:
      exposure:
        include: "*"

给cloud-config-center-3366客户端添加消息总线支持

1.在POM.xml添加如下依赖

<!--添加消息总线RabbitMQ支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2.修改配置文件

server:
  port: 3366

spring:
  application:
    name: config-client
  cloud:
    config:
      label: main
      name: config
      profile: dev
      uri: http://localhost:3344
  #rabbitmq相关配置  15672是web管理界面的端口,5672是MQ访问的端口
  rabbitmq:
    host: 172.16.114.135
    port: 5672
    username: guest
    password: guest
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
management:
  endpoints:
    web:
      exposure:
        include: "*"

测试:启动7001、3344、3355、3366
此时修改GitHub上的配置文件
此时只需要刷新3344,即可让3355、3366动态获取最新的配置文件。

curl -X POST "http://localhost:3344/actuator/bus-refresh"

一次修改,广播通知,处处生效。

其原理就是:
ConfigClient实例都监听MQ中同一个topic(默认是springCloudBus)。当一个服务刷新数据的时候,它会把这个信息放入到Topic中,这样其它监听同一Topic的服务就能得到通知,然后去更新自身的配置。

总结:
所有客户端都监听了一个rabbitMq的topic,我们将信息放入这个topic,所有客户端都可以送到,从而实时更新。

SpringCloud Bus动态刷新定点通知

不想全部通知,只想定点通知。比如只通知3355,不通知3366。

公式:http://localhost:配置中心的端口号/actuator/bus-refresh/{destination}

/bus/refresh请求不再发送到具体的服务实例上,而是发给config server并通过destination参数类指定需要更新配置的服务或实例

这里只通知3355:

curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"

在这里插入图片描述
SpringCloud学习笔记(七)----配置中心Config、消息总线Bus_第14张图片
可以发现,实际上就是通过微服务的名称+端口号进行指定。

你可能感兴趣的:(SpringCloud)