分布式环境下使用 SpringCloud ConfigBus 和 RabbitMQ 刷新配置

分布式环境下使用 SpringCloud ConfigBus 和 RabbitMQ 刷新配置

2020年9月更新

还用什么bus啊config啊MQ啊。。。 直接上nacos了兄弟🤣


Spring Cloud Config

分布式环境微服务提供集中化的外部配置支持。配置服务器为各个不同的微服务应用的共同环境提供了一个中心化的外部配置 ,分为服务端和客户端。那么如何在 SpringCloud 中使用 ConfigBus 和 RabbitMQ?

服务端 server

也称分布式配置中心.是一个独立的微服务应用,用来连接git服务器(默认)并为客户端提供配置信息。

客户端 client

通过制定的配置中心来管理应用资源和业务相关的配置。在启动的时候从配置中心获取和加载配置信息,有利于统一进行配置管理。

这样做的好处有很多,比如:

● 集中管理配置文件:
当服务越来越多,需要进行统一的管理,避免每次改变需要重启服务。

● 不同环境不同配置,动态化配置更新,分环境部署:
可针对不同的环境比如开发、生产、预发布、灰度发布、测试环境有效的分环境部署。互不影响。

● 运行期间可动态调整配置,不需要再每个服务单独修改重启等,且配置变动时可动态感知并生效。

● 将配置信息以Rest接口的形式暴露:

客户端就可以通过接口来动态获取相关配置信息。

● Spring Cloud Config 构建的配置中心,除了适用于 Spring 构建的应用外,也可以在任何其他语言构建的应用中使用。

● Spring Cloud Config 默认采用 Git 存储配置信息,天然支持对配置信息的版本管理。

Spring Cloud Bus

将分布式系统的节点与轻量级消息代理链接。
这可以用于广播状态更改(例如配置更改)或其他管理指令。一个关键的想法是,Bus 就像一个扩展的 Spring Boot 应用程序的分布式执行器,但也可以用作应用程序之间的通信渠道。

Spring Cloud Bus 官方解释

简单说,Bus是用来将分布式系统的服务节点(node)与轻量级的消息系统(MQ)连接起来的框架(bus)。 核心原理其实就是利用消息队列做广播。

所以,首先得有个消息队列,目前官方支持 RabbitMQ 和 kafka。本文选用的是RabbitMQ,至于如何搭建请自行查找相关博客,有很多教程,这里不再赘述。

涉及到的技术&版本如下:

Github 
Rabbit MQ - 3.7.14 
Erlang - 21.3 
SpringCloud - Hoxton.SR1
SpringBoot - 2.2.2RELEASE

构建

在构建前首先在github上创建一个仓库,里面放一些可能用到的配置文件,如:

内容如下:

一、构建 config-server

首先创建server服务cloud-config-center-13344,主要依赖:

<!-- Bus消息总线-RabbitMQ支持 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!-- config-server -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <!--此处的依赖是SpringBoot2.0以后专用的,如果您使用的SpringBoot版本低于2.0请使用spring-cloud-starter-eureka-server-->
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>         
</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>

配置文件:

server:
  port: 13344

spring:
  application:
    name: cloud-config-center-13344
  cloud:
    # config 配置中心
    config:
      server:
        git:
          timeout: 60                                               # 超时时间
          uri: https://github.com/yourgithub.git      # 注意和SSH配置方式区分
          search-paths: mycloud-config                              # 搜索目录
          username: 
          password: 
      label: master                                                 # 读取分支
  # MQ配置
  rabbitmq:
    host: your MQip
    port: 5672           # 默认的端口
    username:    
    password: 

eureka:
  instance:
    instance-id: config-13344   
    prefer-ip-address: true      
  client:
    fetch-registry: true         
    register-with-eureka: true   
    service-url:
      defaultZone: http://eurekaserver1:7001/eureka/,http://eurekaserver2:7002/eureka/,http://eurekaserver3:7003/eureka/

management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: 'bus-refresh'   # 暴露bus用到的刷新配置端点

这里多说一嘴。

关于配置git的方式有两种,一种如上述配置通过uri和用户名及密码来获取连接,还有一种则是通过ssh证书才能获取连接,区别如下:

这种是用户名及密码获取 :https://github.com/xxxx.git
这种是必须要ssh证书验证:git@github.com:xxxx.git

至于如何配置git的ssh证书私钥可以 看这里

需要注意的是, 私钥为BEGIN RSA PRIVATE KEY开头,END RSA PRIVATE KEY结尾。

目前网上关于SSH配置的博文较少,我所见几篇都是官方文档原文,本人通过实测,以下配置可以正常运行,如有问题请留言或联系文章底部邮箱,尽量解答。

spring:
  cloud:
    # config 配置中心
    config:
      server:
        git:
          uri: git@github.com:yourgithub.git        
          ignore-local-ssh-settings: true                          # 激活基于属性的SSH配置
          strict-host-key-checking: false
          # 由于private-key行数过多只截取三行显示。
          private-key: |
            -----BEGIN RSA PRIVATE KEY-----
            MIIJJwIBAAKCAgEAySKaBxpGEmzrDc5vFFFkwSDKzkG6LLw9DJXjab1qtlJuvALC
            wIa1UIJzTSlZ/pLxqh7LuDtFnPUFViik6s3zLZePydY8KiV/c+Tip7laG+J9pj9W
            tzR1zoSxE0fhIpXiCBIK0fG73GxmpDqhl7zY2bywKpUeOAdiNB5bpIx/xg==
            -----END RSA PRIVATE KEY-----
      label: master                                                 # 读取分支

注意点:
private-key: 后面的 | 要有,—–BEGIN RSA PRIVATE KEY—–和 —–END RSA PRIVATE KEY—–也是必须的。

启动后还有个很大概率会出现的错误:
Property ‘spring.cloud.config.server.git.privateKey’ is not a valid private key

这个错误的解决办法网上也是千篇一律诸如在每行后面接\n\或者\转义符。
但本地实测无效。(也有可能在.porperties配置文件下有效)

我这里解决办法为通过 Notepad++ 或其他文本工具,打开本地的 .ssh 文件夹下的 .id_rsa ,注意底部平台及编码。默认为Unix,右键改为windows

然后将内容整体复制到 .yml 配置文件中即可,并不需要手动添加\n\等转移符即可正常启动。

最后在主启动类添加config的注解

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

这样config-server服务就搭建完成了,可以用
http://ip:port/分支/配置文件名 来测试下,若正产返回gitHub中的配置则代表正常。 如:
http://localhost:13344/master/config-dev.yml

二、构建两个 config-client

创建config-client服务cloud-config-client,分13355和13366端口启动 ,主要依赖:


        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

这里的配置文件和上面的server端配置文件不同。

需要bootstrap.yml

# 启动时先加载bootstrap文件
spring:
  cloud:
    config:
      label: master                      
      name: config                       
      profile: dev                      
      uri: http://localhost:13344  
      # 上面四个参数就会拼接成: http://localhost:13344/master/config-dev.yml

# 暴露监控端点
# actuator 提供了很多api(称为:节点) 默认只开放了 health、info两个节点
# 如果需要公开所有 则在配置文件中继续加入 management.endpoints.web.exposure.include=*
management:
  endpoint:
    health:
      show-details: always # 默认never
      # 具体方法和返回内容 可以参考API
      # GET /autoconfig 查看自动配置的使用情况 true
      # GET /configprops 查看配置属性,包括默认配置 true
      # GET /beans 查看bean及其关系列表 true
      # GET /dump 打印线程栈 true
      # GET /env 查看所有环境变量 true
      # GET /env/{name} 查看具体变量值 true
      # GET /health 查看应用健康指标 false
      # GET /info 查看应用信息 false
      # GET /mappings 查看所有url映射 true
      # GET /metrics 查看应用基本指标 true
      # GET /metrics/{name} 查看具体指标 true
      # POST /shutdown 关闭应用 true
      # GET /trace 查看基本追踪信息 true
  endpoints:
    web:
      exposure:
        include: "*"    #  公开所有节点api
  health:
    influxdb:
      enabled: true

application.yml:

server:
  port: 13355  # 另一个则是13366,不贴了

spring:
  application:
    name: config-client
  rabbitmq:
    host: your MQip
    port: 5672           # 默认的端口
    username:    
    password: 

eureka:
  instance:
    instance-id: client-13355    
    prefer-ip-address: true           
  client:
    fetch-registry: true         
    register-with-eureka: true   
    service-url:
      defaultZone: http://eurekaserver1:7001/eureka/,http://eurekaserver2:7002/eureka/,http://eurekaserver3:7003/eureka/

写一个简单的controller用来从13344server服务获取配置信息:

@RestController
@Slf4j
@RefreshScope // spring cloud提供的一种特殊的scope实现,用来实现配置、实例热加载
public class GetConfigController {

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

    @Value("${ips.all}")
    private String ips;

    @Value("${website}")
    private String website;

    @GetMapping("/config")
    String getConfig(){
        log.info("读取到的configInfo  = " + configInfo);
        log.info("读取到的ips = " + ips);
        log.info("读取到的website = " + website);

        JSONObject jo = new JSONObject();
        jo.put("config.info", configInfo);
        jo.put("website", website);
        jo.put("ips", ips);
        return jo.toJSONString(1);
    }

}

在IDEA中配置运行参数,来分两端口口启动:

-Dspring.profiles.active=dev13355 -Dserver.port=13355
-Dspring.profiles.active=dev13366 -Dserver.port=13366

将Eureka启动,最终可以看到已经启动的所有服务:

看一下Eureka:

看一下RabbitWeb的界面可以看到有三个连接:

和最重要的 topic

这个topic就是能够实现动态刷新的关键点。

三、实操

我们修改github中配置文件中 config.info最后的version,由开始的 1 改为 11:

master branch,springcloud-config/config-dev.yml,version=11

然后访问13344:

访问13355和13366还是原始的 ‘1’

我们通过向 config-server13344 端发送一个post请求,实现动态热刷新,不需要重启项目:

在IDEA中,工具-打开rest-client,输入/actuator/bus-refresh/

点击发送,再刷新13355和13366。全变成了 11 。成功!

修改git上的配置文件,再发送post请求来进行消息广播这个操作,可以手动,也可以自动。
关于自动发送可以搜索 gitHub 的 Webhook 

这个功能可以在代码变更的时候,会调用我们设置的地址,来实现我们想达到的目的。

以上就是SpringCloud之Config+Bus+rabbitMQ实现分布式环境下自动刷新配置信息的全部内容,希望对你有所帮助。

Comments

No comments yet. Why don’t you start the discussion?

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注