Springcloud基础知识(10)- Spring Cloud Config (二) | 刷新 Config 配置


在 “Springcloud基础知识(9)- Spring Cloud Config (一) | 搭建 Config 服务端和客户端” 里 SpringcloudDemo03 项目基础上,我们创建了 ConfigServer 和 ConfigClient 子模块。

我们修改 Gitee 上的配置文件 config-dev.yml 后,得到的测试结论:

    (1) 配置更新后,ConfigServer 不需要重启,就从 Git 仓库中获取了最新的配置;
    (2) ConfigClient 需要重启,才能获得最新的配置信息;

很显然,在实际应用中,经常重启一个应用会影响用户体验,而且,有些场合的应用是不允许经常重启的。为了解决不重启 ConfigClient 无法获取最新配置的问题,我们需要手动刷新配置或动态刷新配置。


1. 手动刷新配置

    这里我们对 ConfigClient 进行改造,改造步骤如下。

    1) 修改 ConfigClient 的 pom.xml 文件,引入 Spring Boot actuator 监控模块。

1         <dependency>
2             <groupId>org.springframework.boot</groupId>
3             <artifactId>spring-boot-starter-actuator</artifactId>
4         </dependency>


    2) 修改 src/main/resources/bootstrap.yml 文件,对外暴露 Spring Boot actuator 的监控节点。

1         # Spring Boot actuator 监控
2         management:
3             endpoints:
4                 web:
5                     exposure:
6                         include: "*"   # "*" 表示开启全部节点,多个节点用逗号分隔,比如 "beans,bus-refresh,channels"


    3) 修改 src/main/java/com/example/controller/ConfigController.java 文件,使用 @RefreshScope 注解开启配置刷新。

 1         package com.example.controller;
 2 
 3         import org.springframework.beans.factory.annotation.Value;
 4         import org.springframework.web.bind.annotation.GetMapping;
 5         import org.springframework.web.bind.annotation.RestController;
 6         import org.springframework.cloud.context.config.annotation.RefreshScope;
 7 
 8         @RefreshScope
 9         @RestController
10         public class ConfigController {
11             @Value("${server.port}")
12             private String port;
13             @Value("${config.company}")
14             private String company;
15             @Value("${config.version}")
16             private String version;
17 
18             @GetMapping(value = "/get/config")
19             public String getConfig() {
20                 return "Company: " + company + "<br/>Version:" + version + "<br/>Port:" + port;
21             }
22         }


    4) 运行

        重启 ConfigClient 模块,修改 config-dev.yml 的 version 为 3.0,并提交到 Gitee 仓库,浏览器访问 http://localhost:3001/master/config-dev.yml,显示结果如下:

            config:
                company: com.example
                version: 3.0

        浏览器访问 http://localhost:4001/get/config,显示结果如下:
        
            Company: com.example
            Version:2.0
            Port:4001        

            注:很显然,改造后的 ConfigClient,也无法直接获取到最新配置。

        在命令行下,运行如下命令:

            curl -X POST "http://localhost:4001/actuator/refresh"

        浏览器再次访问 http://localhost:4001/get/config,显示结果如下:

            Company: com.example
            Version:3.0
            Port:4001                   

    5) 手动刷新配置的局限

        通过在 ConfigClient 中引入 Spring Boot actuator 监控组件来监控配置的变化,使我们可以在不重启 Config 客户端的情况下获取到了最新配置。

        这种方式虽然解决了重启 ConfigClient 才能获取最新配置的问题,但另一个问题却也接踵而至,那就是只要配置仓库中的配置发生改变,就需要我们逐个向 ConfigClient 手动发送 POST 请求,通知它们重新拉取配置。

        ConfigClient 是一个一个的服务。在微服务架构中,一个系统往往包含十几甚至几十个服务,如果因为某一个配置文件的修改而向几十个微服务发送 POST 请求,这显然是不合理的。

        那么有没有 “一次通知,处处生效” 的方式呢?答案是肯定的。Spring Cloud Config 配合 Bus 就可以实现配置的动态刷新。


2. Config + Bus 实现配置的动态刷新

    Spring Cloud Bus 又被称为消息总线,它能够通过轻量级的消息代理(例如 RabbitMQ、Kafka 等)将微服务架构中的各个服务连接起来,实现广播状态更改、事件推送等功能,还可以实现微服务之间的通信功能。

    目前 Spring Cloud Bus 支持两种消息代理:RabbitMQ 和 Kafka。

    Spring Cloud Bus 的基本原理:

        Spring Cloud Bus 会使用一个轻量级的消息代理来构建一个公共的消息主题 Topic(默认为“springCloudBus”),这个 Topic 中的消息会被所有服务实例监听和消费。当其中的一个服务刷新数据时,Spring Cloud Bus 会把信息保存到 Topic 中,这样监听这个 Topic 的服务就收到消息并自动消费。

    Spring Cloud Bus 动态刷新配置的原理:

        利用 Spring Cloud Bus 的特殊机制可以实现很多功能,其中配合 Spring Cloud Config 实现配置的动态刷新就是最典型的应用场景之一。

        当 Git 仓库中的配置发生了改变,只需要向某一个服务(既可以是 Config 服务端,也可以是 Config 客户端)发送一个 POST 请求,Spring Cloud Bus 就可以通过消息代理通知其他服务重新拉取最新配置,以实现配置的动态刷新。

    Spring Cloud Bus 实现配置的动态刷新的步骤:

        (1) 当 Git 仓库中的配置发生改变后,运维人员向 Config 服务端发送一个 POST 请求,请求路径为“/actuator/refresh”;
        (2) Config 服务端接收到请求后,会将该请求转发给服务总线 Spring Cloud Bus;
        (3) Spring Cloud Bus 接到消息后,会通知给所有 Config 客户端;
        (4) Config 客户端接收到通知,请求 Config 服务端拉取最新配置;
        (5) 所有 Config 客户端都获取到最新的配置;


    1) 全局广播

        本文以 Kafka 为例,来演示如何使用 Config + Bus 实现配置的动态刷新,关于 Kafka 请参考 “ Springboot 系列 (16) - Springboot+Kafka 实现发布/订阅消息 ”。

        (1) 修改 ConfigServer 模块的 pom.xml 文件,添加 Spring Boot actuator 监控模块和 Spring Cloud Bus 的依赖

1             <dependency>
2                 <groupId>org.springframework.boot</groupId>
3                 <artifactId>spring-boot-starter-actuator</artifactId>
4             </dependency>
5             <dependency>
6                 <groupId>org.springframework.cloud</groupId>
7                 <artifactId>spring-cloud-starter-bus-kafka</artifactId>
8             </dependency>


        (2) 修改 ConfigServer 模块的 src/main/resources/application.yml 文件

 1             server:
 2                 port: 3001 # 端口号
 3             spring:
 4                 application:
 5                     name: spring-cloud-config-server # 服务名
 6                 cloud:
 7                     config:
 8                         server:
 9                             git:
10                                 uri: https://gitee.com/xxx/springcloud-demos-config.git  # 仓库地址
11                                 search-paths:
12                                     - springcloud-demos-config  # 仓库名
13                                 force-pull: true
14                                 username: xxx
15                                 password: xxx
16                             label: master
17                     bus:
18                         trace:
19                             enabled: true
20                     stream:
21                         kafka:
22                             binder:
23                                 brokers: 192.168.0.5:9092       # 192.168.0.5 是 kafka 运行的主机,下同
24                                 zk-nodes: 192.168.0.5:2181
25                                 auto-create-topics: true
26 
27             eureka:
28                 client: # 将客户端注册到 eureka 服务列表内
29                     service-url:
30                         # 将服务注册到 Eureka 集群
31                         defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
32 
33             # Spring Boot actuator 监控
34             management:
35                 endpoints:
36                     web:
37                         exposure:
38                             include: 'bus-refresh'


        (3) 修改 ConfigClient 模块的 pom.xml 文件,添加 Spring Cloud Bus 的依赖

1             <dependency>
2                 <groupId>org.springframework.cloud</groupId>
3                 <artifactId>spring-cloud-starter-bus-kafka</artifactId>
4             </dependency>


        (4) 修改 ConfigClient 模块的 src/main/resources/bootstrap.yml 文件

 1            # bootstrap.yml 是系统级别的,加载优先级高于 application.yml ,负责从外部加载配置并解析
 2             server:
 3                 port: 4001 # 端口号
 4             spring:
 5                 application:
 6                     name: spring-cloud-config-client # 服务名
 7                 cloud:
 8                     config:
 9                         label: master # 分支名称
10                         name: config  # 属性名称,config-dev.yml 中的 config
11                         profile: dev  # 环境名  config-dev.yml 中的 dev
12                         uri: http://localhost:3001 # Spring Cloud Config 服务端(配置中心)地址
13                     bus:
14                         trace:
15                             enabled: true
16                     stream:
17                         kafka:
18                             binder:
19                                 brokers: 192.168.0.5:9092
20                                 zk-nodes: 192.168.0.5:2181
21                                 auto-create-topics: true
22 
23             eureka:
24                 client: # 将客户端注册到 eureka 服务列表内
25                     service-url:
26                     # 将服务注册到 Eureka 集群
27                     defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
28 
29             # Spring Boot actuator 监控
30             management:
31                 endpoints:
32                     web:
33                         exposure:
34                             include: "*"   # "*" 表示开启全部节点,多个节点用逗号分隔,比如 "beans,bus-refresh,channels"


        (5) 打包,配置 configserver-3001、configclient-4001、configclient-4002

 1             eureka
 2               |- configserver-3001
 3               |    |- ConfigServer-1.0-SNAPSHOT.jar  
 4               |    |- application.yml
 5               |    |- start.bat
 6               |
 7               |- configclient-4001
 8               |    |- ConfigClient-1.0-SNAPSHOT.jar  
 9               |    |- application.yml (由 bootstap.yml 改名)
10               |    |- start.bat
11               |
12               |- configclient-4002
13                    |- ConfigClient-1.0-SNAPSHOT.jar  
14                    |- application.yml (由 bootstap.yml 改名)
15                    |- start.bat          


            configclient-4002 和 configclient-4001 运行的端口号是 4002 和 4001,其它配置一样。

        (6) 运行

            确保 Kafka 已经处于正常运行状态,本文的 Kafka 运行在内网的 192.168.0.5 主机。

            依次启动 server-7001、configserver-3001、configclient-4001 和 configclient-4002。

            浏览器访问 http://localhost:4001/get/config 和 http://localhost:4002/get/config,显示结果如下:

                Company: com.example
                Version:3.0
                Port:4001

            修改 config-dev.yml 的 version 为 4.0,并提交到 Gitee 仓库。
            
            在命令行下,运行如下命令:

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

            浏览器访问 http://localhost:4001/get/config 和 http://localhost:4002/get/config,应该都显示结果如下:

                Company: com.example
                Version:4.0
                Port:4001 (或 4002 )

    2) 定点通知

        定点通知就是不再通知所有的 Config 客户端,而是根据需求只通知其中某一个 Config 客户端。

        使用 Spring Cloud Bus 实现定点通知的方法十分简单,只要我们在发送 POST 请求时使用以下格式即可。

            http://{hostname}:{port}/actuator/bus-refresh/{destination}

        参数说明如下:

            {hostname}: 表示 Config 服务端的主机地址,既可以是域名,也可以是 IP 地址。
            {port}:表示 Config 服务端的端口号.
            {destination}:表示需要定点通知的 Config 客户端(微服务),由 Config 客户端的服务名(spring.application.name)+ 端口号(server.port)组成。

        示例:

            修改 config-dev.yml 的 version 为 5.0,并提交到 Gitee 仓库。  

            在命令行下,运行如下命令:

                curl -X POST "http://localhost:3001/actuator/bus-refresh/spring-cloud-config-client:4002"

            浏览器访问 http://localhost:4001/get/config,显示结果如下:

                Company: com.example
                Version:4.0
                Port:4001

            浏览器访问 http://localhost:4002/get/config,显示结果如下:

                Company: com.example
                Version:5.0
                Port:4002


posted @ 2022-06-30 21:05  垄山小站  阅读(298)  评论(0)    收藏  举报