1.概述
Spring Cloud Bus是用來將分佈式系統的結點與輕量級消息系統連接起來的框架,它整合了Java事件處理機制和消息中間件的功能,Spring Cloud Bus目前支持的MQ有:RAbbitMQ和Kafka。Spring Cloud Bus可以使Spring Cloud Config實現配置的動態刷新。
觀察下圖,運維發送/bus/refresh的POST請求給其中一個Client,Client將消息發送給消息總線,最初收到POST請求的Client拉取最新的配置信息,監聽Spring Cloud Bus的其他Client收到消息後,也去配置中心拉取最新配置信息。這種模式是不推薦的,下面會說原因。
Spring Cloud Bus能管理和傳播分佈式系統間的消息,類似一個分佈式執行器,可用於廣播狀態更改、事件推送等,也可以作爲微服務之間的通信信道。
在微服務架構系統中,通常會使用輕量級的消息代理來構建一個共用的消息主題,讓所有的微服務實例都連接上來,這個主題中產生的消息會被所有實例監聽和消費,所以稱爲消息總線。在總線上的實例還可以發送消息給總線,讓總線上的其他監聽者獲取消息。
觀察下圖,運維發送/bus/refresh請求給配置中心,配置中心會獲取最新的配置文件,併發送一個消息給消息總線,監聽消息總線的其他Client會收到消息,並從配置中心拉取最新的配置文件。這種模式是推薦使用的。
用戶向Config Server發送update的post請求,Config Server更新配置並把消息發送到總線的Topic中,Config Client實例監聽MQ中同一個Topic(默認是Spring Cloud Bus),所有監聽同一個Topic的服務就都能收到通知,然後更新自身的配置。
2.RabbitMQ環境配置
1.Window版本
RabbitMQ服務器是用Erlang語言編寫,需要下載Erlang運行環境,下載地址:http://erlang.org/download/otp_win64_21.3.exe,然後安裝RabbitMQ,下載地址:https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.14/rabbitmq-server-3.7.14.exe,在RabbitMQ的sbin目錄下,cmd下運行rabbitmq-plugins enable rabbitmq_management添加可視化插件,運行之後,可以在安裝目錄看到幾個插件,啓動RabbitMQ Service-start,在瀏覽器訪問http://localhost:15672/,輸入用戶名和密碼,都是guest。
2.Linux版本
使用Docker安裝RabbitMQ,輸入命令docker pull rabbitmq:management拉取rabbitmq鏡像,記得選擇帶management的,否則沒有管理後臺。使用命令docker run -d -p 5672:5672 -p 15672:15672 rabbitmq:management啓動RabbitMQ服務。瀏覽器訪問http://192.168.0.123:15672/,即可看到管理後臺,輸入用戶名和密碼,都是guest。
3.Spring Cloud Bus動態刷新全局廣播
爲了演示廣播的效果,我們還需要一個Config-Client,於是參考cloud-config-client-3355創建cloud-config-client-3366。記得修改端口號,其他地方和cloud-config-client-3355幾乎沒什麼變化,爲了區分具體Client,在ConfigClientController的請求中,把端口號輸出。
上面提到了兩種方案:一種是發給某一個ConfigClient,另一種是發給ConfigServer,這裏推薦後者。原因如下:
- ConfigClient也是一個微服務,它有自己的業務需要處理,如果把刷新配置的工作放在它上面,就破壞了單一職責原則。
- 如果在某臺ConfigClient加了刷新功能,它處理自身業務邏輯可能會受到影響,可能會拖慢本身的業務。
- 如果ConfigClient遷移,要對地址進行修改,增加工作量,相對來說,ConfigServer遷移概率小一些。
所以,我們選擇發送/bus/refresh給ConfigServer,ConfigServer獲取最新配置信息後發送消息給Bus,監聽Bus的ConfigClient收到消息後,從ConfigServer上拉取最新的配置信息。
修改cloud-config-server-3344添加消息總線支持,pom.xml中加入spring-cloud-starter-bus-amqp的座標。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
修改cloud-config-server-3344指定MQ的信息,並暴露bus-refresh端口。
server:
port: 3344
spring:
application:
name: cloud-config-center
cloud:
config:
server:
git:
uri: https://github.com/WangShaoYang/Spring-Cloud.git # Github上的倉庫地址
search-paths: # 搜索目錄,即配置文件的目錄
- cloud-config-center-3344/
label: master # 讀取分支
rabbitmq: # 指定MQ的信息
host: 192.168.0.123
port: 5672
username: guest
password: guest
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
management:
endpoints:
web:
exposure:
include: 'bus-refresh' # 暴露bus-refresh端口
修改cloud-config-client-3355和cloud-config-client-3366添加消息總線支持,pom.xml中加入spring-cloud-starter-bus-amqp的座標,和cloud-config-server-3344的pom.xml裏是一樣的。
修改cloud-config-client-3355和cloud-config-client-3366的bootstrap.yml,指明MQ的信息,並暴露bus-refresh端點,MQ的信息和cloud-config-server-3344保持一致即可,另外注意縮進對齊,因爲cloud-config-client-3355和cloud-config-client-3366之前暴露的端點信息是"*"了,所以這裏就不用改了。
啓動RabbitMQ服務,先後啓動Eureka7001,CloudServer3344,CloudConfig3355,CloudConfig3366模塊,如果啓動太快報錯,就一個一個的啓動。啓動完成後,訪問http://eureka7001.com:7001/查看微服務註冊信息,訪問RabbitMQ管理後臺,確定RabbitMQ正常啓動了。訪問http://localhost:3344/master/config-dev.yml,http://localhost:3355/configInfo,http://localhost:3366/configInfo確保都能正常訪問後,去GitHub上修改config-dev.yml的內容,由運維工程師發送如下命令(如正常情況下,沒有任何返回信息),注意發送給ConfigServer這臺機器。
C:\Users\WangShaoYang>curl -X POST "http://localhost:3344/actuator/bus-refresh"
刷新成功後,再次訪問http://localhost:3344/master/config-dev.yml,http://localhost:3355/configInfo,http://localhost:3366/configInfo,可以發現它們獲取到了最新的配置信息。查看RabbitMQ的管理後臺,查看Exchanges標籤會看到一個springCloudBus的Topic,正是通過這個Topic,3355和3366客戶端接收到刷新消息,自我刷新它們的配置文件。
4.Spring Cloud Bus動態刷新定點通知
上面的消息通知是發送給了所有監聽springCloudBus的Client,如果只希望通知某些Client,就需要在發送curl請求的時候,做一些改動,將實際想發送的Client指定一下即可。
比如,我修改配置中心的配置文件,只希望3355Client生效,那麼發送的url爲:curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"。說明一下,這裏的請求實際上還是發送給ConfigServer,也就是發送給localhost:3344,和之前不同的是,在bus-refresh後,帶了一個參數,表明RabbitMQ需要通知給微服務名稱(對應spring.application.name的值,也是註冊進Eureka中微服務的名稱)爲config-client,端口號(對應server.port的值)爲3355的微服務。
演示一下,在GitHub上修改config-dev.yml的內容,發送通知給ConfigServer,讓其通知3355Client更新配置信息(正常情況下,沒有任何返回信息)。
C:\Users\WangShaoYang>curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"
訪問http://localhost:3344/master/config-dev.yml,http://localhost:3355/configInfo,http://localhost:3366/configInfo查看效果,3344信息更新,3355信息更新,3366信息沒變,試驗成功。