天天看点

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

前言

众所周知,在微服务领域,将会拆分出多个 子服务,每个服务的粒度都很小,并且每个服务都需要进行相关的 配置才能运行,但是如此多的子服务,每个服务都进行相关的配置,修改时也要找到对应的配置文件进行修改,将是一件非常麻烦的事情,所以SpringCloud提供了 一个ConfigServer来解决这个问题。

采用Config,来为微服务提供一个集中化的外部 配置支持,各个不同微服务应用的所有环境提供了一个中心化的 外部配置。

Config分为服务端和客户端两部分:

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

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

服务端

在GitHub上创建自己的config服务

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

新建服务端项目

1、pom文件

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
           

2、配置文件

server:
  port: 3344

spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          uri: https://github.com/1742268440Zhy/springcloud-config.git  #github上面的git仓库名字
#          uri: [email protected]:1742268440Zhy/springcloud-config.git  #github上面的git仓库名字
          # 搜索目录
          search-paths:
            - springcloud-config
      # 读取分支
      label: master
           

注:有的童鞋可能写uri:[email protected]:1742268440Zhy/springcloud-config.git 会报错cannot clone or checkout repository,可能是因为ssl公私钥设置的 有问题,可以检查一下在电脑本地是否能通过git clone命令拉取下来代码,如果不能,就检查一下ssl的公私钥配置。如果能就可能是其他原因了,具体什么原因这里没有进行详细的解决,只是将ssl的地址改为了https的地址,这样就能通过安全https路径进行访问了。

3、主启动类

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

4、运行访问

启动服务,输入地址访问:http://localhost:3344/master/config-dev.yml

查看结果:

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

客户端

1、pom

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
           

2、配置文件

server:
  port: 3355

spring:
  application:
    name: cloud-config-client
  cloud:
    #config客户端配置
    config:
      # 读取分支
      label: master
      name: config #配置文件名称
      profile: dev # 读取后缀名称
      uri: http://localhost:3344 #配置中心地址
           

3、启动类

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

4、业务代码

@RestController
public class ConfigClientController {
    @Value("${config.info}")
    private String configInfo;

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

5、启动 测试

启动服务端和客户端,访问地址 :http://localhost:3355/configInfo

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

得到的内容即从服务端拉取到的内容。

6、存在问题

此时我们在github上修改 配置文件中的内容,重新刷新服务端和客户端,看结果:

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus
分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

可以发现服务端因为是直接连接到git地址,所以git中的内容刷新,服务端可以直接 获取到新的内容。但是客户端监听的是 3344的服务器,而此时3344服务器更新后并没有通知到客户端。

此时我们需要手动进行相关配置,使客户端动态刷新。

修改3355客户端模块如下

pom引入actuator监控:

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

修改yml,暴露监控端口:

#暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"
           

业务类上加@RefreshScope注解:

@RestController
@RefreshScope
public class ConfigClientController {
    @Value("${config.info}")
    private String configInfo;

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

再次运行,此时修改git上的内容,修改完之后,需要主动发送post请求刷新3355:

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

查看服务端和客户端的效果:

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus
分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

7、再次思考

目前我们只有一个客户端服务,如果来多个客户端服务,同时监听一个服务端,那么github上一旦有变动,就需要进行手动通知到所有的客户端,这将是一件非常麻烦的事情,所以我们在之前的基础上再次做了更新,引入SpringCloud Bus 消息总线机制。

SpringCloud Bus

引入

Bus能够实现分布式自动刷新配置功能,它结合SpringCloud config使用可以实现配置的动态刷新。SpringCloud Bus被称为消息总线机制,他能够实现将分布式系统的节点与轻量级消息系统连接起来,管理和传播系统间的消息,就像一个分布式的执行器,可以广播状态更改、事件推送等,也可以当做微服务间的通信通道,目前支持的 消息代理为RabbitMq和kafka。

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

基于以上原理就出现了两种设计思想:

1、利用消息总线触发一个客户端/bus/refresh,从而刷新所有客户端配置

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

2、利用消息总线触发一个服务端ConfigServer的/bus/refresh端点,从而刷新所有客户端配置

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

我们最终选取第二种设计思想,原因如下:

1、第一种打破了微服务的职责单一性,因为微服务本身是业务模块,它本不应该承担配置刷新的职责

2、第一种设计破坏了微服务各节点的对等性

3、第一种有一定的局限性,例如,微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动刷新那就会增加更多的修改

动态刷新全局广播

再按照3355服务,添加一个实例服务3366.

3355和3366客户端都更改如下配置:

1、pom中引入总线amqp的依赖

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

2、更改配置文件

配置文件中添加MQ的相关配置内容

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

3344服务端更改如下配置:

1、引入依赖

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

2、更改配置文件

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus
分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

启动测试

先后启动3344/3355/3366三个服务,最初结果如下

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus
分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus
分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

此时更改github上的文件内容,并执行如下命令:

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus
分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

重新刷新三个服务,结果如下:

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus
分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus
分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

由此就达到了一次更新通知,所有监听节点能够全部更改的结果。

动态刷新定点通知

那么问题又来了,如果我只想通知一部分客户端更新,而不想通知全部客户端更新呢?

比如 只通知3355不通知3366.

很简单,在执行通知语句的时候只需要套用下面的公式即可:

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

比如直通知3355,则执行下面的语句:

分布式配置中心+总线——config+bus前言服务端客户端SpringCloud Bus

继续阅读