1. 消息總線概述
1.1 分布式配置的動态重新整理問題
- Linux運維修改Github上的配置檔案内容做調整
- 重新整理3344,發現ConfigServer配置中心立刻響應
- 重新整理3355,發現ConfigClient用戶端沒有任何響應
- 3355沒有變化除非自己重新開機或者重新加載
- 難道每次運維修改配置檔案,用戶端都需要重新開機?
1.2 消息總線加強Config
SpringCloud Bus配合SpringCloud Config使用可以實作配置的動态重新整理。
用SpringCloud Config時,我們可以實作配置資訊手動的動态重新整理,也就是遠端配置資訊發生改變後,需要告訴服務端配置資訊發生變化後,服務端才會更新配置資訊,而現在我們想要實作分布式自動重新整理配置資訊功能,這就需要我們使用SpringCloud Bus消息總線配合SpringCloud Config實作配置資訊的動态重新整理。
SpringCloud Bus是用來将分布式系統的節點與輕量級消息系統連接配接起來的架構,它整合了Java的事件處理機制和消息中間件的功能,SpringCloud Bus目前支援兩種消息代理:RabbitMQ和Kafka。
SpringCloud Bus能管理和傳播分布式系統間的消息,就像一個分布式執行器,可用于廣播狀态更改、事件推送等, 也可以當做微服務間的通信通道。
1.2 為什麼被稱為總線
在微服務架構的系統中,通常會 使用輕量級的消息代理 來建構一個 共用的消息主題,并讓系統中所有微服務執行個體都連接配接上來,由于 該主題中産生的消息會被所有執行個體監聽和消費,是以稱它為消息總線。在總線上的各個執行個體,都可以友善地廣播一些需要讓其他連接配接在該主題上的執行個體都知道的消息。
基本原理:SpringCloud Config用戶端的執行個體都監聽消息隊列中的同一個主題(topic)(預設是SpringCloud Bus),當一個伺服器重新整理資料的時候,它會把這個資訊放入到主題中,這樣其他監聽了同一主題的服務就能得到通知,然後去更新自身的配置。
1.3 安裝RabbitMQ
直接使用docker-compose安裝吧!
通路位址看是否安裝成功:http://localhost:15672,輸入賬号并登入,預設guest/guest
2. SpringCloud Bus動态重新整理全局廣播
在學習SpringCloud Config的時候我們已經建立了服務cloud-config-client-3355作為Config的用戶端,這裡為了示範廣播效果,我們增加複雜度,再以3355為模闆再制作另一個Config的用戶端3366,建立Module:cloud-config-client-3366,其結構和cloud-config-client-3355類似,修改下服務端口号即可。
修改以下3355/3366的controller,用于區分
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${server.port}")
private String serverPort;
@Value("${server.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo() {
return "serverPort:" + serverPort + "\t configInfo:" + configInfo;
}
}
2.1 消息總線的兩種設計思想
方案一
利用消息總線 觸發一個用戶端/bus/refresh端點,而後重新整理所有用戶端的配置:
方案二
利用消息總線 觸發一個服務端ConfigServer的/bus/refresh端點,而後重新整理所有用戶端的配置:
兩種方案對比
明顯第二種架構更加合适,第一種架構不合适的原因主要有:
- 打破了微服務的職責單一性,因為微服務本身是業務子產品,它本不應該承擔配置重新整理的職責
- 破壞了微服務各節點的對等性
- 有一定的局限性,比如在微服務遷移時,它的網絡位址常常會發生變化,此時如果想要做到自動重新整理,那就會增加更多的修改
是以雖然從技術上兩種方案都可以實作,但是無疑在技術選型上我們應該選擇第二種方案。
2.2 3344服務端添加消息總線支援
在其POM檔案中添加使用RabbitMQ實作消息總線的依賴:
<!--添加消息總線RabbitMQ支援-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
然後在其yml配置檔案中添加RabbitMQ的相關配置,暴露SpringCloud Bus重新整理配置的端點
# RabbitMQ相關配置
spring:
rabbitmq:
host: mpolaris.top
port: 5672
username: admin
password: 1234321
# 暴露總線重新整理配置的端點
management:
endpoints:
web:
exposure:
include: 'bus-refresh'
2.3 3355/3366用戶端添加消息總線支援
在其POM檔案中添加RabbitMQ實作總線的依賴(同ConfigServer的相關依賴):
<!--添加消息總線RabbitMQ支援-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
然後在其yml配置檔案中添加RabbitMQ的相關配置:
# RabbitMQ相關配置
spring:
rabbitmq:
host: mpolaris.top
port: 5672
username: admin
password: 1234321
2.4 測試
按順序啟動Eureka服務注冊中心7001,ConfigServer配置中心3344,ConfigClient配置中心用戶端3355/3366,此時遠端GitHub上的配置資訊如下:
server:
info: my name is config server , this is master/config-dev.yml
分别通路配置中心及其配置中心用戶端的服務中心,發現結果都是一樣的。
然後将Gitee遠端的配置資訊中info加一個
=>
,然後對服務配置中心發送POST請求:
curl -X POST "{配置中心的位址}/actuator/bus-refresh"
# 如此時我們該發送的POST請求為:
curl -X POST "http://localhost:3344/actuator/bus-refresh"
此時再通路配置中心及用戶端的配置資訊,發現所有服務的配置資訊都得到了更新:
打開RabbitMQ的控制台,我們可以發現有一個交換機,這就對應消息總線發送消息的交換機:
3. SpringCloud Bus動态重新整理定點通知
在全局廣播中,我們更新配置檔案的資訊對所有服務都進行了通知,但是假設我們隻想通知3355,而不想通知3366又該怎麼辦呢,這就需要我們用定點通知的方法通知3355,也就是說我們進行消息通知時隻指定具體某個執行個體生效而不是全部生效,這種情況下就需要修改我們發送的POST請求:
curl -X POST "http://{配置中心的位址}/actuator/bus-refresh/{destination}"
這樣的話,actuator/bus-refresh請求就不再發送到具體的服務執行個體上,而是發給ConfigServer配置中心并通過destination參數指定需要更新配置的服務或執行個體。其中destination具體為 微服務+端口号。
比如現在我們修改遠端配置檔案,但是我們隻想通知3355的配置更新資訊,而不想通知3366,此時我們發送的POST請求就應該是:
curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"