咱们在springcloud(七):配置中心svn示例和refresh中讲到,若是须要客户端获取到最新的配置信息须要执行refresh
,咱们能够利用webhook的机制每次提交代码发送请求来刷新客户端,当客户端愈来愈多的时候,须要每一个客户端都执行一遍,这种方案就不太适合了。使用Spring Cloud Bus能够完美解决这一问题。html
Spring cloud bus经过轻量消息代理链接各个分布的节点。这会用在广播状态的变化(例如配置变化)或者其余的消息指令。Spring bus的一个核心思想是经过分布式的启动器对spring boot应用进行扩展,也能够用来创建一个多个应用之间的通讯频道。目前惟一实现的方式是用AMQP消息代理做为通道,一样特性的设置(有些取决于通道的设置)在更多通道的文档中。java
Spring cloud bus被国内不少都翻译为消息总线,也挺形象的。你们能够将它理解为管理和传播全部分布式项目中的消息既可,其实本质是利用了MQ的广播机制在分布式的系统中传播消息,目前经常使用的有Kafka和RabbitMQ。利用bus的机制能够作不少的事情,其中配置中心客户端刷新就是典型的应用场景之一,咱们用一张图来描述bus在配置中心使用的机制。git
根据此图咱们能够看出利用Spring Cloud Bus作配置更新的步骤:github
咱们选择上一篇文章springcloud(八):配置中心服务化和高可用版本的示例代码来改造,MQ咱们使用RabbitMQ来作示例。web
客户端spring-cloud-config-client改造spring
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
须要多引入spring-cloud-starter-bus-amqp
包,增长对消息总线的支持安全
## 刷新时,关闭安全验证 management.security.enabled=false ## 开启消息跟踪 spring.cloud.bus.trace.enabled=true spring.rabbitmq.host=192.168.9.89 spring.rabbitmq.port=5672 spring.rabbitmq.username=admin spring.rabbitmq.password=123456
配置文件须要增长RebbitMq的相关配置,这样客户端代码就改造完成了。网络
依次启动spring-cloud-eureka、spring-cloud-config-server、spring-cloud-config-client项目,在启动spring-cloud-config-client项目的时候咱们会发现启动日志会输出这样的一条记录。架构
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项目的端口为800三、8004依次启动,这样测试环境就准备好了。启动后eureka后台效果图以下:并发
咱们先分别测试一下服务端和客户端是否正确运行,访问:http://localhost:8001/neo-config/dev
,返回信息:
{ "name": "neo-config", "profiles": [ "dev" ], "label": null, "version": null, "state": null, "propertySources": [ { "name": "https://github.com/ityouknow/spring-cloud-starter/config-repo/neo-config-dev.properties", "source": { "neo.hello": "hello im dev" } } ] }
说明server端都正常读取到了配置信息。
依次访问:http://localhost:8002/hello
、http://localhost:8003/hello
、http://localhost:8004/hello
,返回:hello im dev
。说明客户端都已经读取到了server端的内容。
如今咱们更新neo-config-dev.properties
中neo.hello
的值为hello im dev update
并提交到代码库中,访问:http://localhost:8002/hello
依然返回hello im dev
。咱们对端口为8002的客户端发送一个/bus/refresh
的post请求。在win下使用下面命令来模拟webhook.
curl -X POST http://localhost:8002/bus/refresh
执行完成后,依次访问:http://localhost:8002/hello
、http://localhost:8003/hello
、http://localhost:8004/hello
,返回:hello im dev update
。说明三个客户端均已经拿到了最新配置文件的信息,这样咱们就实现了图一中的示例。
在上面的流程中,咱们已经到达了利用消息总线触发一个客户端bus/refresh
,而刷新全部客户端的配置的目的。但这种方式并不优雅。缘由以下:
所以咱们将上面的架构模式稍微改变一下
这时Spring Cloud Bus作配置更新步骤以下:
这样的话咱们在server端的代码作一些改动,来支持bus/refresh
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> </dependencies>
须要多引入spring-cloud-starter-bus-amqp
包,增长对消息总线的支持
server: port: 8001 spring: application: name: spring-cloud-config-server cloud: config: server: git: uri: https://github.com/ityouknow/spring-cloud-starter/ # 配置git仓库的地址 search-paths: config-repo # git仓库地址下的相对地址,能够配置多个,用,分割。 username: username # git仓库的帐号 password: password # git仓库的密码 rabbitmq: host: 192.168.0.6 port: 5672 username: admin password: 123456 eureka: client: serviceUrl: defaultZone: http://localhost:8000/eureka/ ## 注册中心eurka地址 management: security: enabled: false
配置文件增长RebbitMq的相关配置,关闭安全验证。这样server端代码就改造完成了。
依次启动spring-cloud-eureka、spring-cloud-config-server、spring-cloud-config-client项目,改动spring-cloud-config-client项目端口为800三、8004依次启动。测试环境准备完成。
按照上面的测试方式,访问server端和三个客户端测试都可以正确返回信息。一样修改neo-config-dev.properties
中neo.hello
的值为hello im dev update
并提交到代码库中。在win下使用下面命令来模拟webhook触发server端bus/refresh
.
curl -X POST http://localhost:8001/bus/refresh
执行完成后,依次访问:http://localhost:8002/hello
、http://localhost:8003/hello
、http://localhost:8004/hello
,返回:hello im dev update
。说明三个客户端均已经拿到了最新配置文件的信息,这样咱们就实现了上图中的示例。
某些场景下(例如灰度发布),咱们可能只想刷新部分微服务的配置,此时可经过/bus/refresh
端点的destination参数来定位要刷新的应用程序。
例如:/bus/refresh?destination=customers:8000
,这样消息总线上的微服务实例就会根据destination参数的值来判断是否须要要刷新。其中,customers:8000
指的是各个微服务的ApplicationContext ID。
destination参数也能够用来定位特定的微服务。例如:/bus/refresh?destination=customers:**
,这样就能够触发customers微服务全部实例的配置刷新。
一些场景下,咱们可能但愿知道Spring Cloud Bus事件传播的细节。此时,咱们能够跟踪总线事件(RemoteApplicationEvent的子类都是总线事件)。
跟踪总线事件很是简单,只需设置spring.cloud.bus.trace.enabled=true
,这样在/bus/refresh
端点被请求后,访问/trace
端点就可得到相似以下的结果:
{ "timestamp": 1495851419032, "info": { "signal": "spring.cloud.bus.ack", "type": "RefreshRemoteApplicationEvent", "id": "c4d374b7-58ea-4928-a312-31984def293b", "origin": "stores:8002", "destination": "*:**" } }, { "timestamp": 1495851419033, "info": { "signal": "spring.cloud.bus.sent", "type": "RefreshRemoteApplicationEvent", "id": "c4d374b7-58ea-4928-a312-31984def293b", "origin": "spring-cloud-config-client:8001", "destination": "*:**" } }, { "timestamp": 1495851422175, "info": { "signal": "spring.cloud.bus.ack", "type": "RefreshRemoteApplicationEvent", "id": "c4d374b7-58ea-4928-a312-31984def293b", "origin": "customers:8001", "destination": "*:**" } }
这个日志显示了customers:8001
发出了RefreshRemoteApplicationEvent事件,广播给全部的服务,被customers:9000
和stores:8081
接受到了。想要对接受到的消息自定义本身的处理方式的话,能够添加@EventListener
注解的AckRemoteApplicationEvent和SentApplicationEvent类型到你本身的应用中。或者到TraceRepository类中,直接处理数据。
这样,咱们就可清晰地知道事件的传播细节。
/bus/refresh
BUG/bus/refresh
有一个很严重的BUG,一直没有解决:对客户端执行/bus/refresh
以后,挂到总线的上的客户端都会从Eureka注册中心撤销登记;若是对server端执行/bus/refresh
,server端也会从Eureka注册中心撤销登记。再用白话解释一下,就是原本人家在Eureka注册中心注册的好好的,只要你对着它执行一次/bus/refresh
,马上就会从Euraka中挂掉。
其实这个问题挺严重的,原本你利用/bus/refresh
给全部的节点来更新配置信息呢,结果把服务从Euraka中给搞掉了,那么若是别人须要调用客户端的服务的时候就直接歇菜了。不知道国内有童鞋公司在生产中用到这个功能没有,用了不就很惨烈。在网上搜索了一下,国内网友和国外网友都遇到过不少次,可是一直没有解决,很幸运就是我在写这篇文章的前几天,Netflix修复了这个问题,使用Spring Cloud最新版本的包就能够解决这个问题。由此也能够发现Spring Cloud还在快速的发展中,最新的版本可能也会有一些不稳定性,可见路漫漫而修远兮。
在pom中使用Spring Cloud的版本,解决这个bug.
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Dalston.SR1</spring-cloud.version> </properties>
主要是这句:<spring-cloud.version>Dalston.SR1</spring-cloud.version>
,详情能够参考本文示例中的代码
BUG的讨论和解决过程能够看github上面这两个issue:
参考:
Config Server——使用Spring Cloud Bus自动刷新配置
做者:纯洁的微笑
出处:http://www.ityouknow.com/
版权归做者全部,转载请注明出处