SpringCloud Config -----Bus

SpringCloud-Config

概述

Spring Cloud Config 为分布式系统中的外部化配置提供服务器端和客户端支持。使用配置服务器,您可以集中管理所有环境中应用程序的外部属性。

简单理解:比如现在有 3 个微服务它们同时连接一个数据库,假设数据库的IP变了,或者密码,等修改了,那么我们就必须在三个微服务上修改,如果微服务过多,大量的修改也会出现问题。于是有了SpringCloud-Config,它的作用就是

  1. 统一的配置抽取出来并放到GitHub 或者 码云等代码托管中心
  2. 创建一个(Spring-Cloud-ConfigSever)服务端,负责读取GitHub 或者 码云上的配置文件
  3. 在微服务端配置连接(Spring-Cloud-ConfigSever)服务端,从而读取配置文件,即修改文件只需要修改配置信息,只需要修改GitHub 或者 码云即可。

原理图:

解决问题

Spring Cloud Config解决了微服务配置的中心话,版本控制,平台独立,语言独立等问题。

特点

  • 提供服务端和客户端支持(Spring Cloud Cloud Server 和 Spring Cloud Config Client)
  • 集中式管理分布式环境下的应用部署
  • 属性值的加密和解密
  • 基于Spring容器,无缝集成Spring
  • 可用任何语言开发的程序
  • 默认使用Git,可用进行版本管理

配置中心服务端搭建

首先需要准备一个Git远程仓库,不管时码云,还是GitHub都可以自己选择,并在仓库中存放一些yaml配置文件。我这里准备的如下。

开始搭建

  1. 创建微服务启动父项目,负责管理依赖。

  2. 创建模块 cloud-config-center-3344

  3. 导入pom

    <dependencies>
        <!--SpringCloud config Server SpringCloud 配置服务器-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <!--连接 consul 的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
    
        <!--spring-boot-web 模块 常用的3个-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</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>
        <!--热部署插件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--测试插件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--lombok 依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    
  4. 添加application.yaml

    server:
      port: 3344
    spring:
      application:
        name: cloud-config-center
      cloud:
        config:
          server:
            git:
              uri: https://gitee.com/Rampants/spring-cloud-config.git  #仓库地址 码云仓库最好使用https连接
              search-paths:
                - SpringCloud Config    # 搜索目录,
          label: master     # 默认分支
    
        consul:
          # 服务的主机
          host: localhost
          # 服务的端口号
          port: 8500
          discovery:
            # 注册到服务中心的名称
            service-name: ${spring.application.name}
    
  5. 主启动类

    package com.wyx.cloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.config.server.EnableConfigServer;
    
    
    @SpringBootApplication
    @EnableDiscoveryClient	//服务注册与发现
    @EnableConfigServer		// 自动开启配置服务
    public class ConfigCenterMain3344 {
    
        public static void main(String[] args) {
            SpringApplication.run(ConfigCenterMain3344.class,args);
        }
    }
    
  6. 启动应用,访问:http://localhost:3344/config-dev.yaml 可以查看到我们在git仓库存放的值

访问规则

/{application}/{profile}[/{label}] 
/{application}-{profile}.yml 
/{label}/{application}-{profile}.yml 
/{application}-{profile}.properties 
/{ label}/{application}-{profile}.properties

application :对应应用名称

profile:对应环境

yml或者properties :文件后缀名

label:分支

比如在仓库中存在一个文件 config-dev.yaml

那么:config是应用名称 、 dev是环境 、yaml对应文件后缀名、label对应该文件所在的分支

# 例子
localhost:3344/foo/development 
localhost:3344/foo/development/master 
localhost:3344/foo/development,db/master 
localhost:3344/foo-development.yml 
localhost:3344/foo-db.properties
localhost:3344/master/foo-db.properties

客户端搭建

  1. 创建新模块 cloud-config-client-4111

  2. 导入pom

    <dependencies>
    
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <!--4.X版本在spring-cloud-starter-config剔除了bootstrap,需要自己导入-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
    
        <!--连接 consul 的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
    
        <!--spring-boot-web 模块 常用的3个-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</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>
        <!--热部署插件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--测试插件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--lombok 依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    
    
  3. 添加 application.yaml,这里需要做修改,需要将application.yaml的名字改为bootstrap.yaml

    server:
      port: 4111
    
    spring:
      application:
        name: config-client
      cloud:
        config:
          label: master   # 分支名
          name: config    # 配置文件的名字,对应上面访问规则的application
          profile: dev    # 对应上面的环境,
          uri: http://localhost:3344  # SpringCloud 配置中心的地址
    
        consul:
          # 服务的主机
          host: localhost
          # 服务的端口号
          port: 8500
          discovery:
            # 注册到服务中心的名称
            service-name: ${spring.application.name}
    
  4. 主启动类

    package com.wyx.cloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class ConfigClientMain4111 {
        public static void main(String[] args) {
            SpringApplication.run(ConfigClientMain4111.class,args);
        }
    }
    
    
  5. 业务类

    package com.wyx.cloud.controller;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class ConfigClientController {
    
        @Value("${config.info}")
        private String configInfo;
    
        @GetMapping("/getInfo")
        public String getInfo(){
            return configInfo;
        }
    }
    

    访问:http://localhost:4111/getInfo 可以得到

    在项目中配置的config-dev.yaml 配置的 config.info的内容

到此,配置完成。

自动刷新功能完善

在刚才配置的环境中,当我们修改了远程仓库的文件内容时,访问Config-Server端能实现实时更新,

但是访问Config-Clinet并不能实时更新(具体可以自己演示)必须要重启Config-Clinet才能实现实时更新,很麻烦,于是我们需要对项目经行一定的修改,让它实现自动刷新功能。

  1. 添加pom中添加健康检查

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    
  2. 在业务类Controller层添加刷新作用域的注解,修改后如下

    package com.wyx.cloud.controller;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RefreshScope	//新添加
    public class ConfigClientController {
    
        @Value("${config.info}")
        private String configInfo;
    
        @GetMapping("/getInfo")
        public String getInfo(){
            return configInfo;
        }
    }
    
  3. 当修改了仓库中的内容时,修改者需要发送一条Post 请求,内容如下

    # 对应地址
    curl -X POST "http://localhost:4111/actuator/refresh"
    

    测试即可。

上面我们可以知道通过发送命令可以实现自动刷新,但是如果微服务太多我们该怎么办??

我们可以使用Spring Cloud Bus来实现自动刷新具体参考以下地址

http:XXXXXX;

配置中心加密解密实现(后续更新)

为什么要使用

在远程仓库中,许多配置文件比如数据库密码,远程地址等等,都是敏感信息,所以我们需要对其实现加密解密功能

对称加密

对称加密是最快速,最简单的一种加密方式,加密和解密用的都是同样的密钥。

加密环境说明

对应JDK版本在JDK 8之前的我们需要下载已经jce的加密包

下载地址

JDK8的下载地址: https://www.oracle.com/java/technologies/javase-jce8-downloads.html

所有版本的下载地址:https://www.oracle.com/java/technologies/javase-jce-all-downloads.html

下载完成后解压:

将解压的文件local_policy.jarUS_export_policy.jar 的jar包 放到jdk安装目录的jre目录下bin目录下的security目录下,如果自己配了JRE 运行环境最好也添加,

SpringCloud-Bus

概述

Spring Cloud Bus 将分布式系统的节点与轻量级消息代理连接起来。这随后可用于广播状态更改(例如配置更改)或其他管理指令。AMQP 和 Kafka 代理实现包含在项目中。或者,在类路径上找到的任何Spring Cloud Stream绑定器都可以作为传输开箱即用。

简单理解,就是就是收到消息后利用消息队列,在将其广播到其他的微服务上。目前只支持RabbirMQKafka

什么是SpringCloud-Bus

在微服务系统架构中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统中所有的微服务实例都订阅这个主题,由于该消息主题的信息会被所有实例监听和消费,所有称它为消息总线

解决SpringCloud Config 中手动刷新的问题

介绍完这些,我们来完善,在Spring Cloud Config Center中由于修改git仓库导致,需要需要手动刷新,但是如果微服务过多,刷新缓慢的问题。使用技术(SpringCloud-Bus 和 RabbitMQ)

环境搭建

  1. 搭建RabbitMQ,具体如何搭建参考 RabbitMQ;

  2. 新建模块 cloud-config-client-4112,cloud-config-client-4113(搭建步骤cloud-config-client-4111 一样)这里就给出一个cloud-config-client-4112的列子,宁外一个修改端口即可

  3. 修改pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <!--4.X版本在spring-cloud-starter-config剔除了bootstrap,需要自己导入-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
    
        <!--连接 consul 的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
    
        <!--spring-boot-web 模块 常用的3个-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</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>
        <!--热部署插件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--测试插件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--lombok 依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    
  4. 添加 bootstrap.yaml

    server:
      port: 4112  #4113记得修改端口
    
    spring:
      application:
        name: config-client
      cloud:
        config:
          label: master   # 分支名
          name: config    # 配置文件的名字,对应上面访问规则的application
          profile: dev    # 对应上面的环境,
          uri: http://localhost:3344  # SpringCloud 配置中心的地址
    
        consul:
          # 服务的主机
          host: localhost
          # 服务的端口号
          port: 8500
          discovery:
            # 注册到服务中心的名称
            service-name: ${spring.application.name}
    
    # 暴露端口
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
  5. 主启动类

    package com.wyx.cloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    public class ConfigClientMain4112 {
        public static void main(String[] args) {
            SpringApplication.run(ConfigClientMain4112.class,args);
        }
    }
    // 记得修改类名
    
  6. 业务类

    package com.wyx.cloud.controller;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RefreshScope
    public class ConfigClientController {
    
        @Value("${config.info}")
        private String configInfo;
    
        @Value("${server.port}")
        private String serverPort;
    
        @GetMapping("/getInfo")
        public String getInfo(){
            return configInfo+"服务端口"+serverPort;
        }
    }
    
  7. 同时也修改cloud-config-client-4111的业务类如上

现在启动 cloud-config-center-3344,cloud-config-client-4111,cloud-config-client-4112,cloud-config-client-4113

如果修改了git仓库的内容,那么我们需要发送如下三个请求才能实现刷新

curl -X POST "http://localhost:4111/actuator/refresh"
curl -X POST "http://localhost:4112/actuator/refresh"
curl -X POST "http://localhost:4113/actuator/refresh"

解决办法

现在我们利用消息队列来解决这个问题

方案一:利用消息总线触发一个客户端/bus/refresh,而刷新所有客户端的配置

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

方案一和方案二都可以实现,但是方案一是有缺点的

方案一缺点:

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

方案二解决步骤:

  1. config-center,以及所有的config-client都添加如下依赖

    <!--健康检查依赖是不能省的,前面有这里不添加-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    
  2. 在confeig-center(配置中心服务端)的application.yaml添加

    spring:
      rabbitmq:
        host: 47.97.218.81
        port: 5672
        username: admin
        password: 970699
    
    # 暴露总线刷新端口
    management:
      endpoints:
        web:
          exposure:
            include: 'bus-refresh'
    
  3. 在config-client(配置中心客户端)的bootstarp.yaml添加rabbitmq的连接信息

    spring:
      rabbitmq:
        host: 47.97.218.81
        port: 5672
        username: admin
        password: 970699
    

现在如果修改了 git 仓库的内容,我们只需要手动刷新 配置中心服务端即可

curl -X POST "http://localhost:3344/actuator/busrefresh"

如果想要单独刷新某个节点,比如只刷新配置中心客户端的4112端口,可以使用如下命令

# 下面的config-client是微服务的应用名后面接端口
curl -X POST "http://localhost:3344/actuator/busrefresh/config-client:4112"

总结

  1. 修改Git仓库。

  2. 管理员向配置中心-服务端发送请求

    curl -X POST "http://localhost:3344/actuator/busrefresh"
    
  3. 请求将消息发布到消息队列的主题模式(RabittMQ)

  4. 配置中心客户端订阅主题,如果有消息则刷新自己。

posted @   橘子有点甜  阅读(99)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示