前文已经介绍了consul服务应用,config服务应用,但是这两部分都是各自独立应用,并没有结合使用。同时对于config server,单个服务可以通过动态刷新进行更新配置文件,但是多个服务更新配置文件需要调用多个/refresh,较为复杂。对此,可以通过消息总线Bus结合RabbitMQ实现动态更新配置文件并进行个服务间推送,从而实现服务的动态更新。
config结合bus,通过rabbitmq实现动态刷新原理分析:
该方案的架构如上图所示,其中应用了Git仓库、Config Server、以及微服务“Service A”的三个实例,这三个实例中都引入了Spring Cloud Bus,他们都连接到了RabbitMQ的消息总线上。
当我系统启动起来之后,“Service A”的三个实例会请求Config Server以获取配置信息,Config Server根据应用配置的规则从Git仓库中获取配置信息并返回。此时,若我们需要修改“Service A”的属性。首先,通过Git管理工具去仓库中修改对应的属性值,但是这个修改并不会触发“Service A”实例的属性更新。我们向“Service A”的实例3发送POST请求,访问/bus/refresh接口。此时,“Service A”的实例3就会将刷新请求发送到消息总线中,该消息事件会被“Service A”的实例1和实例2从总线中获取到,并重新从Config Server中获取他们的配置信息,从而实现配置信息的动态更新。
而从Git仓库中配置的修改到发起/bus/refresh的POST请求这一步可以通过Git仓库的Web Hook来自动触发。由于所有连接到消息总线上的应用都会接受到更新请求,所以在Web Hook中就不需要维护所有节点内容来进行更新,从而解决了通过Web Hook来逐个进行刷新的问题。
上面的例子中,我们通过向服务实例请求Spring Cloud Bus的/bus/refresh接口,从而触发总线上其他服务实例的/refresh。但是有些特殊场景下(比如:灰度发布),我们希望可以刷新微服务中某个具体实例的配置。
Spring Cloud Bus对这种场景也有很好的支持:/bus/refresh接口还提供了destination参数,用来定位具体要刷新的应用程序。比如,我们可以请求/bus/refresh?destination=customers:9000,此时总线上的各应用实例会根据destination属性的值来判断是否为自己的实例名,若符合才进行配置刷新,若不符合就忽略该消息。
destination参数除了可以定位具体的实例之外,还可以用来定位具体的服务。定位服务的原理是通过使用Spring的PathMatecher(路径匹配)来实现,比如:/bus/refresh?destination=customers:**,该请求会触发customers服务的所有实例进行刷新。
注:以上内容引入http://blog.didispace.com/springcloud7/
其中consul和rabbitmq服务在接下来工程中保证已经启动。
1)新建工程second-consul-config-server。其中pom.xml如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>com.fiberhomegroupId>
<artifactId>second-fiberhomeartifactId>
<version>0.0.1-SNAPSHOTversion>
parent>
<artifactId>second-consul-config-serverartifactId>
<packaging>jarpackaging>
<name>second-consul-config-servername>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-config-serverartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-bus-amqpartifactId>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-consul-dependenciesartifactId>
<version>1.0.1.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
project>
注:引入consul和bus消息总线依赖。
2)创建application.properties。
server.port=8888
#######config-repo#######
spring.cloud.config.profile=dev
spring.cloud.config.server.git.uri=https://github.com/moyu2012/second-fiberhome.git
spring.cloud.config.server.git.searchPaths=second-fiberhome-repo
######consul#############
spring.cloud.consul.host=192.168.56.101
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.enabled=true
spring.cloud.consul.discovery.instance-id=consul-config-server
spring.cloud.consul.discovery.hostname=localhost
spring.cloud.consul.discovery.port=${server.port}
spring.cloud.consul.discovery.serviceName=consul-config-server
spring.cloud.consul.discovery.healthCheckUrl=http://192.168.56.1:${server.port}/health
spring.cloud.consul.discovery.healthCheckInterval=10s
spring.cloud.consul.discovery.tags=dev
#####rabbitmq############
spring.rabbitmq.host=192.168.56.101
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
注:consul和rabbitmq部署在虚机中,ip为192.168.56.101,本地服务ip为192.168.56.1
3)创建启动类ConsulConfigServerApplication.java
package com.fiberhome;
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 ConsulConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsulConfigServerApplication.class, args);
}
}
4)启动该服务,完成config server服务,具有consul和rabbitmq下bus总线服务。
1)新建工程second-consul-config-client。其中pom如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>com.fiberhomegroupId>
<artifactId>second-fiberhomeartifactId>
<version>0.0.1-SNAPSHOTversion>
parent>
<artifactId>second-consul-config-clientartifactId>
<packaging>jarpackaging>
<name>second-consul-config-clientname>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-bus-amqpartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-configartifactId>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-consul-dependenciesartifactId>
<version>1.0.1.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
project>
2)创建appliaction.properties.
server.port=8901
#config
spring.application.name=second-config
spring.cloud.config.profile=dev
#spring.cloud.config.label=master
spring.cloud.config.uri=http://127.0.0.1:8888/
#spring.cloud.config.failFast=true
spring.cloud.consul.host=192.168.56.101
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.enabled=true
spring.cloud.consul.discovery.serviceName=consul-config-client-sub
spring.cloud.consul.discovery.healthCheckUrl=http://192.168.56.1:${server.port}/health
spring.cloud.consul.discovery.healthCheckInterval=10s
spring.cloud.consul.discovery.tags=dev
spring.cloud.consul.discovery.port=${server.port}
#rabbitmq
spring.rabbitmq.host=192.168.56.101
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbiymq.password=guest
spring.cloud.bus.trace.enabled=true
3)创建创建启动类ConsulConfigClientApplication.java和配置信息读取接口VersionController.java.
package com.fiberhome;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulConfigClientSubApplication
{
public static void main(String[] args) {
SpringApplication.run(ConsulConfigClientSubApplication.class, args);
}
}
package com.fiberhome.web;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RefreshScope
@RestController
public class VersionController {
@Value("${version}")
private String version;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@RequestMapping(value = "/version",method = RequestMethod.GET)
public String version(){
return this.version;
}
}
4)启动该服务,完成config client服务,具有consul和rabbitmq下bus总线服务。
second-consul-config-server
second-consul-config-client
second-consul-config-client-sub
rabbitmq连接信息如下:
由以上可知,三个服务在consul中完成服务注册和服务发现功能,同时都连接到了mq上,接下来测试bus总线功能。
当前github端配置信息为:
那么请求second-consul-config-client,看看version接口配置信息:
请求second-consul-config-client-sub,看看version接口配置信息:
接下来修改git仓库内容:
此时任意更新client端的bus总线刷新接口:/bus/refresh post请求
完成调用,更新配置文件内容,此时查看两个client端,version值:
client:
client-sub:
由以上可知,通过rabbitmq,完成消息总线的所有配置文件更新操作。
该工程源码见github:https://github.com/moyu2012/second-fiberhome