配置中心(spring cloud config+spring cloud bus)配置中心和消息总线(高级应用)
本文中示例代码的引用版本:
org.springframework.boot 版本 :1.5.3.RELEASE
org.springframework.cloud 版本:Camden.SR1
( 2.1.0.RELEASE,Greenwich.M1)在server端应用没有能测试成功,降低版本了。以后有时间在试。)
示例代码-码云 https://gitee.com/sharps/springcloud
在第五章、spring cloud—配置中心(spring cloud config)+git应用讲到,如果需要客户端获取到最新的配置信息需要执行refresh,我们可以利用webhook的机制每次提交代码发送请求来刷新客户端,当客户端越来越多的时候,需要每个客户端都执行一遍,这种方案就不太适合了。使用Spring Cloud Bus可以完美解决这一问题。
Spring Cloud Bus
Spring cloud bus通过轻量消息代理连接各个分布的节点。这会用在广播状态的变化(例如配置变化)或者其他的消息指令。Spring bus的一个核心思想是通过分布式的启动器对spring boot应用进行扩展,也可以用来建立一个多个应用之间的通信频道。目前唯一实现的方式是用AMQP消息代理作为通道,同样特性的设置(有些取决于通道的设置)在更多通道的文档中。
Spring cloud bus被国内很多都翻译为消息总线,也挺形象的。大家可以将它理解为管理和传播所有分布式项目中的消息既可,其实本质是利用了MQ的广播机制在分布式的系统中传播消息,目前常用的有Kafka和RabbitMQ。利用bus的机制可以做很多的事情,其中配置中心客户端刷新就是典型的应用场景之一,我们用一张图来描述bus在配置中心使用的机制。
根据此图我们可以看出利用Spring Cloud Bus做配置更新的步骤:
1、提交代码触发post给客户端A发送bus/refresh
2、客户端A接收到请求从Server端更新配置并且发送给Spring Cloud Bus
3、Spring Cloud bus接到消息并通知给其它客户端
4、其它客户端接收到通知,请求Server端获取最新配置
5、全部客户端均获取到最新的配置
项目示例
我们使用RabbitMQ来做示例。
第一步:改造0604spring-cloud-config-client为spring-cloud-config-client (node1\node2\node3)
1、添加依赖
引入spring-cloud-starter-bus-amqp包,增加对消息总线的支持
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<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>
</dependencies>
2、配置文件
application.properties
node1:
spring.application.name=spring-cloud-config-client
server.port=8002
management.security.enabled=false
node2:
spring.application.name=spring-cloud-config-client
server.port=8004
management.security.enabled=false
node3:
spring.application.name=spring-cloud-config-client
server.port=8005
management.security.enabled=false
bootstrap.properties(node1\node2\node3)
spring.cloud.config.name=test-config
spring.cloud.config.profile=dev
#非服务注册中心式,直接指向server端地址的配置
#spring.cloud.config.uri=http://localhost:8001/
spring.cloud.config.label=master
#开启Config服务发现支持
spring.cloud.config.discovery.enabled=true
#指定server端的name,也就是server端spring.application.name的值
spring.cloud.config.discovery.serviceId=spring-cloud-config-server
# 注册中心eurka地址 增加了eureka注册中心的配置 增加security 认证
eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/
# 开启消息跟踪
spring.cloud.bus.trace.enabled=true
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123456
3、测试
依次启动spring-cloud-eureka、spring-cloud-config-server、spring-cloud-config-client项目,在启动spring-cloud-config-client-(node1/nodel2/node3)项目的时候我们会发现启动日志会输出这样的一条记录。
2017-05-26 17:05:38.568 INFO 21924 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/bus/refresh],methods=[POST]}" onto public void org.springframework.cloud.bus.endpoint.RefreshBusEndpoint.refresh(java.lang.String)
说明客户端已经具备了消息总线通知的能力了,为了更好的模拟消息总线的效果,我们更改客户端spring-cloud-config-client项目的端口为8003、8004依次启动,这样测试环境就准备好了。启动后eureka后台效果图如下:
我们先分别测试一下服务端和客户端是否正确运行,访问:http://localhost:8001/test-config/dev,返回信息:
{
"name": "test-config",
"profiles": [
"dev"
],
"label": "master",
"version": "41511811229bc94faa93a0311708716d54ca6081",
"state": null,
"propertySources": [
{
"name": "https://gitee.com/sharps/springcloud.git/config-repo/test-config-dev.properties",
"source": {
"test.hello": "hello im dev success!"
}
}
]
}
说明server端都正常读取到了配置信息。
依次访问:http://localhost:8002/hello、http://localhost:8004/hello、http://localhost:8005/hello,返回:hello im dev success!。说明客户端都已经读取到了server端的内容。
现在我们更新test-config-dev.properties 中test.hello的值为hello im dev success update并提交到代码库中,访问:http://localhost:8002/hello 依然返回hello im dev success。我们对端口为8002的客户端发送一个/bus/refresh的post请求。在命令窗口下使用下面命令来模拟webhook.
curl -X POST http://localhost:8002/bus/refresh
执行完成后,依次访问:http://localhost:8002/hello、http://localhost:8004/hello、http://localhost:8005/hello ,返回:hello im dev update。说明三个客户端均已经拿到了最新配置文件的信息,这样我们就实现了图一中的示例。
改进版本
在上面的流程中,我们已经到达了利用消息总线触发一个客户端bus/refresh,而刷新所有客户端的配置的目的。但这种方式并不优雅。原因如下:
打破了微服务的职责单一性。微服务本身是业务模块,它本不应该承担配置刷新的职责。
破坏了微服务各节点的对等性。
有一定的局限性。例如,微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动刷新,那就不得不修改WebHook的配置。
因此我们将上面的架构模式稍微改变一下
这时Spring Cloud Bus做配置更新步骤如下:
1、提交代码触发post请求给bus/refresh
2、server端接收到请求并发送给Spring Cloud Bus
3、Spring Cloud bus接到消息并通知给其它客户端
4、其它客户端接收到通知,请求Server端获取最新配置
5、全部客户端均获取到最新的配置
这样的话我们在server端的代码做一些改动,来支持bus/refresh
1、添加依赖
org.springframework.cloud spring-cloud-config-server org.springframework.cloud spring-cloud-starter-bus-amqp org.springframework.cloud spring-cloud-starter-eureka 需要多引入spring-cloud-starter-bus-amqp包,增加对消息总线的支持2、配置文件
server:
port: 8001
spring:
application:
name: spring-cloud-config-server
cloud:
config:
server:
git:
uri: https://gitee.com/sharps/springcloud.git # 配置git仓库的地址
search-paths: config-repo # git仓库地址下的相对地址,可以配置多个,用,分割。
username: # git仓库的账号
password: # git仓库的密码
bus:
trace:
enabled: true
rabbitmq:
host: 127.0.0.1
port: 5672
username: admin
password: 123456
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8000/eureka/
management:
security:
enabled: false
配置文件增加RebbitMq的相关配置,关闭安全验证。这样server端代码就改造完成了。
3、测试
依次启动spring-cloud-eureka、spring-cloud-config-server、spring-cloud-config-client项目,改动spring-cloud-config-client项目端口为8003、8004依次启动。测试环境准备完成。
按照上面的测试方式,访问server端和三个客户端测试均可以正确返回信息。同样修改test-config-dev.properties 中test.hello的值为hello im dev update并提交到代码库中。在命令行下使用下面命令来模拟webhook触发server端bus/refresh.
curl -X POST http://localhost:8001/bus/refresh
执行完成后,依次访问:http://localhost:8002/hello、http://localhost:8004/hello、http://localhost:8005/hello,返回:hello im dev update。说明三个客户端均已经拿到了最新配置文件的信息,这样我们就实现了上图中的示例。
项目节点
08spring-cloud-config-eureka-bus-nosecurtiy
---->0801spring-cloud-eureka 说明:服务注册中心
---->0802spring-cloud-config-server-node1 说明:提供配置文件的存储、以接口的形式将配置文件的内容提供出去。
---->0804spring-cloud-config-client-node1
---->0805spring-cloud-config-client-node2
---->0806spring-cloud-config-client-node3