Spring Cloud Bus提供了批量刷新配置的機制,它使用輕量級的消息代理(例如RabbitMQ、Kafka等)鏈接分佈式系統的節點,這樣就能夠經過Spring Cloud Bus廣播配置的變化或者其餘的管理指令。使用Spring Cloud Bus後的架構如圖9-2所示。java
圖9-2 使用Spring Cloud Bus的架構圖git
由圖可知,微服務A的全部實例經過消息總線鏈接到了一塊兒,每一個實例都會訂閱配置更新事件。當其中一個微服務節點的/bus/refresh端點被請求時,該實例就會向消息總線發送一個配置更新事件,其餘實例得到該事件後也會更新配置。web
下面咱們以RabbitMQ爲例,爲你們講解如何使用Spring Cloud Bus實現配置的自動刷新。spring
(1) 安裝RabbitMQ。RabbitMQ的安裝很是簡單,本書再也不贅述。bootstrap
(2) 建立項目microservice-config-client-refresh-cloud-bus
安全
(3) 爲項目添加spring-cloud-starter-bus-amqp
的依賴。網絡
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
(4) 在bootstrap.yml中添加如下內容:架構
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
management:
security:
enabled: false #是否開啓actuator安全認證mvc
(1) 啓動microservice-config-serverapp
(2) 啓動microservice-config-client-refresh-cloud-bus,可發現此時控制檯打印相似於如下的內容:
[ 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)
說明此時有一個/bus/refresh
端點
(3) 將microservice-config-client-refresh-cloud-bus的端口改爲8082,再啓動一個節點。
(4) 訪問http://localhost:8081/profile ,可得到結果:dev-1.0。
(4) 將git倉庫中的microservice-foo-dev.properties文件內容改成profile=dev-1.0-bus
(5) 發送POST請求到其中一個Config Client節點的的/bus/refresh端點,例如:
curl -X POST http://localhost:8081/bus/refresh
藉助Git倉庫的WebHook,咱們就可輕鬆實現配置的自動刷新。如圖9-3所示。
圖9-3 Git WebHooks設置
藉助Git倉庫的WebHook,咱們就可輕鬆實現配置的自動刷新。如圖9-3所示。(6) 訪問兩個Config Client節點的/profile端點,會發現兩個節點都會返回dev-1.0-bus
,說明配置內容已被刷新。
某些場景下(例如灰度發佈),咱們可能只想刷新部分微服務的配置,此時可經過/bus/refresh端點的destination參數來定位要刷新的應用程序。
例如:/bus/refresh?destination=customers:9000
,這樣消息總線上的微服務實例就會根據destination參數的值來判斷是否須要要刷新。其中,customers:9000
指的是各個微服務的ApplicationContext ID。
destination參數也能夠用來定位特定的微服務。例如:/bus/refresh?destination=customers:**
,這樣就能夠觸發customers微服務全部實例的配置刷新。
擴展閱讀:關於ApplicationContext ID
默認狀況下,ApplicationContext ID是spring.application.name:server.port,詳見org.springframework.boot.context.ContextIdApplicationContextInitializer.getApplicationId(ConfigurableEnvironment)
方法。
http://www.itmuch.com/spring-cloud-code-read/spring-cloud-code-read-spring-cloud-bus/
在前面的示例中,咱們經過請求某個微服務的/bus/refresh端點的方式來實現配置刷新,但這種方式並不優雅。緣由以下:
(1) 打破了微服務的職責單一性。微服務自己是業務模塊,它本不該該承擔配置刷新的職責。
(2) 破壞了微服務各節點的對等性。
(3) 有必定的侷限性。例如,微服務在遷移時,它的網絡地址經常會發生變化,此時若是想要作到自動刷新,那就不得不修改WebHook的配置。
咱們不妨改進一下咱們的架構。
圖9-4 使用Spring Cloud Bus的架構圖
如圖9-4,咱們將Config Server也加入到消息總線中,並使用Config Server的/bus/refresh端點來實現配置的刷新。這樣,各個微服務只須要關注自身的業務,而再也不承擔配置刷新的職責。
1.在springcloud-configServer中配置bus,加入pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
2.springcloud-configServer中配置bus ym文件
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
management:
security:
enabled: false #是否開啓actuator安全認證
3.在微服務端springcloud-ssmServer配置bus接收
pom.xml
<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>
application.properties
#mq
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
management.security.enabled=false
在須要自動刷新的位置加入@RefreshScope 例如
package com.pupeiyuan.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RefreshScope public class ConfigClientController { @Value("${multiple.datasource.master.InitialSize}") private String profile; @GetMapping("/profile") public String getProfile() { return this.profile; } }
利用webhook自動請求,配置/bus/refresh到springcloud-configServer項目,springcloud-configServer在利用bus傳播特性,經過mq傳播到指定客戶端進行更新
一些場景下,咱們可能但願知道Spring Cloud Bus事件傳播的細節。此時,咱們能夠跟蹤總線事件(RemoteApplicationEvent的子類都是總線事件)。
跟蹤總線事件很是簡單,只需設置spring.cloud.bus.trace.enabled=true
,這樣在/bus/refresh端點被請求後,訪問/trace端點就可得到相似以下的結果:
{ "timestamp": 1481098786017, "info": { "signal": "spring.cloud.bus.ack", "event": "RefreshRemoteApplicationEvent", "id": "66d172e0-e770-4349-baf7-0210af62ea8d", "origin": "microservice-foo:8081", "destination": "**" } },{ "timestamp": 1481098779073, "info": { "signal": "spring.cloud.bus.sent", "type": "RefreshRemoteApplicationEvent", "id": "66d172e0-e770-4349-baf7-0210af62ea8d", "origin": "microservice-config-server:8080", "destination": "**:**" } }...
這樣,咱們就可清晰地知道事件的傳播細節。