上一篇Spring Cloud微服务配置中心-Config Server 中,我们实现了使用Gitlab托管配置文件集成配置中心功能,实现微服务配置统一管理。不过现实使用中,我们还需要实现配置文件更改,各个服务在不重新发布的情况下实时读取最新的配置。

Spring Cloud Bus 实现配置中心实时刷新_java

实现原理

1、ConfigServer(配置中心服务端)从远端git拉取配置文件并在本地git一份,ConfigClient(微服务)从ConfigServer端获取自己对应 配置文件;

2、当远端gitlab仓库配置文件发生改变,ConfigServer如何通知到ConfigClient端,即ConfigClient如何感知到配置发生更新?

Spring Cloud Bus会向外提供一个http接口,/actuator/bus-refresh。我们将这个接口配置到远程的gitlab的webhook上,当git上的文件内容发生变动时,就会自动调用接口。Bus就会通知config-server,config-server会发布更新消息到消息总线的消息队列中,其他服务订阅到该消息就会信息刷新,从而实现整个微服务进行自动刷新。

实现方式一

某个微服务承担配置刷新的职责

Spring Cloud Bus 实现配置中心实时刷新_java_02

1、提交配置触发post调用客户端A的bus/refresh接口

2、客户端A接收到请求从Server端更新配置并且发送给Spring Cloud Bus总线

3、Spring Cloud bus接到消息并通知给其它连接在总线上的客户端,所有总线上的客户端均能收到消息

4、其它客户端接收到通知,请求Server端获取最新配置

5、全部客户端均获取到最新的配置

存在问题:

1、打破了微服务的职责单一性。微服务本身是业务模块,它本不应该承担配置刷新的职责。2、破坏了微服务各节点的对等性。3、有一定的局限性。WebHook的配置随着承担刷新配置的微服务节点发生改变。

改进方式二


配置中心Server端承担起配置刷新的职责,原理图如下:



1、提交配置触发post请求给server端的bus/refresh接口

2、server端接收到请求并发送给Spring Cloud Bus总线

3、Spring Cloud bus接到消息并通知给其它连接到总线的客户端

4、其它客户端接收到通知,请求Server端获取最新配置

5、全部客户端均获取到最新的配置


这里使用方式二

安装RabbitMQ

推荐使用docker的方式一键安装

docker pull rabbitmq--5672为服务访问端口  --15672为web ui访问端口docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 -v `pwd`/data:/var/lib/rabbitmq --hostname myRabbit -e RABBITMQ_DEFAULT_VHOST=my_vhost  -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin ea2bf0a30abf  docker exec -it c1a0bcec221e rabbitmq-plugins enable rabbitmq_management


配置中心pom引入依赖


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

cation.yml

完整如下



客户端pom引入依赖

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

bootstrap.yml添加rabbitmq依赖



rabbitmq:  host: 10.60.25.178  port: 5672  username: admin  password: admin  virtual-host: my_vhost

添加注解:@RefreshScope添加在需要刷新的位置

@RestController@RefreshScopepublic class HelloController { @Value("${hello}") private String name;  @RequestMapping("/tell-me-your-name") public String tellName()  {  return this.name;    } }

先后启动server端和client端,post请求访问http://localhost:8001/actuator/bus-refresh,发现修改配置文件后,新配置可以成功同步到客户端。


使用Webhook,自动刷新


    当然不能每次修改配置文件都要手动Post刷新配置,这里使用Gitlab的webhook功能,webhook配置如下:

这里敲黑板: 需要注意的是webhook要配置/monitor端点,而不是之前的/actuator/bus-refresh,否则会出现400 error,原因是调用之前的端点会引起参数反序列化异常,参数传递错误。使用monitor端点配置中心还需要添加如下依赖。

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


配置完毕,请求正常

Spring Cloud Bus 实现配置中心实时刷新_java_03

本以为大功告成,但是发现配置文件并没有刷新成功。纳尼?!!


查看客户端debug日志发现如下

2020-10-30 13:17:19.698 [springCloudBus.anonymous.nC62OqLTRJKv39uBbDo5mw-1] DEBUG o.springframework.cloud.bus.DefaultBusPathMatcher - matchMultiProfile : hv-administration-dev:**, hv-administration:8088:07684e380a89adc6129d633c1a4ea218

这段日志相关代码如下

1
2
3
4
5
6
7
8
9
protected boolean matchMultiProfile(String pattern, String idToMatch) {
 log.debug("matchMultiProfile : " + pattern + ", " + idToMatch);
 // 省略不相关代码 ...
}

public boolean match(String pattern, String path) {
 log.debug("In match: " + pattern + ", " + path);
 return !this.delagateMatcher.match(pattern, path) ? this.matchMultiProfile(pattern, path) : true;
}

发现正则与发过来的不匹配

正则---   hv-administration-dev:**发过来的 --- hv-administration:8088:07684e380a89adc6129d633c1a4ea218

查看官方文档关于spring.cloud.bus.id的描述
Spring Cloud Bus 实现配置中心实时刷新_java_04
可以看到每个应用都有一个Service ID, 默认的值是app:index:id的组装,规则是:

app:如果vcap.application.name存在则使用vcap.application.name,否则使用spring.application.name(默认值为application)
index:优先使用vcap.application.instance_index,否则依次使用spring.application.indexlocal.server.portserver.port0
id:如果vcap.application.instance_id存在则使用vcap.application.instance_id,否则给一个随机值

从上面的日志中,我们看到是app:index:id中的index不一致,有如下两种修改方法

方法一:


设置vcap.application.instance_index


vcap:  application:  instance_index: ${spring.cloud.config.profile}


方法二:


修改bus.id匹配规则


spring:  application:    name: hv-administration  cloud:    config:      uri: http://localhost:8001      profile: dev      fail-fast: true    bus:      id: ${spring.application.name}:${spring.cloud.config.profile}:${random.value}

注意spring.application.namespring.cloud.config.profile要提前定义好

这里直接使用第二种方法,客户端pom修改如下

spring:  application:    name: hv-administration  cloud:    config:      uri: http://localhost:8001      profile: dev      fail-fast: true    bus:      id: ${spring.application.name}:${spring.cloud.config.profile}:${random.value}

修改完毕,webhook测试自动请求成功200,配置文件也成功刷新!