【前面的話】書接上文SpringCloud之Config,如果沒有看過(guò)可以先移步去看一下。在上一篇文章中提到了配置刷新的問題,如果需要刷新配置就需要客戶端執(zhí)行refresh,我們可以利用webhook的機(jī)制每次提交代碼發(fā)送請(qǐng)求來(lái)刷新客戶端,當(dāng)客戶端越來(lái)越多的時(shí)候,需要每個(gè)客戶端都執(zhí)行一遍,這種方案就不太適合了。使用Spring Cloud Bus可以完美解決這一問題。
壹、Spring Cloud Bus的簡(jiǎn)介
Spring cloud bus通過(guò)輕量消息代理連接各個(gè)分布的節(jié)點(diǎn)。這會(huì)用在廣播狀態(tài)的變化(例如配置變化)或者其他的消息指令。Spring bus的一個(gè)核心思想是通過(guò)分布式的啟動(dòng)器對(duì)spring boot應(yīng)用進(jìn)行擴(kuò)展,也可以用來(lái)建立一個(gè)多個(gè)應(yīng)用之間的通信頻道。目前唯一實(shí)現(xiàn)的方式是用AMQP消息代理作為通道,同樣特性的設(shè)置(有些取決于通道的設(shè)置)在更多通道的文檔中。
貳、解決方案
方案一:
- Spring cloud bus被國(guó)內(nèi)很多都翻譯為消息總線,也挺形象的。大家可以將它理解為管理和傳播所有分布式項(xiàng)目中的消息既可,其實(shí)本質(zhì)是利用了MQ的廣播機(jī)制在分布式的系統(tǒng)中傳播消息,目前常用的有Kafka和RabbitMQ。利用bus的機(jī)制可以做很多的事情,其中配置中心客戶端刷新就是典型的應(yīng)用場(chǎng)景之一,我們用一張圖來(lái)描述bus在配置中心使用的機(jī)制。

根據(jù)此圖我們可以看出利用Spring Cloud Bus做配置更新的步驟:
1、提交代碼觸發(fā)post給客戶端A發(fā)送/actuator/bus-refresh
2、客戶端A接收到請(qǐng)求從Server端更新配置并且發(fā)送給Spring Cloud Bus
3、Spring Cloud bus接到消息并通知給其它客戶端
4、其它客戶端接收到通知,請(qǐng)求Server端獲取最新配置
5、全部客戶端均獲取到最新的配置
方案二:
- 在方案一中我們已經(jīng)到達(dá)了利用消息總線觸發(fā)一個(gè)客戶端/actuator/bus-refresh,而刷新所有客戶端的配置的目的。但這種方式并不優(yōu)雅。原因如下:
打破了微服務(wù)的職責(zé)單一性。微服務(wù)本身是業(yè)務(wù)模塊,它本不應(yīng)該承擔(dān)配置刷新的職責(zé)。
破壞了微服務(wù)各節(jié)點(diǎn)的對(duì)等性。
有一定的局限性。例如,微服務(wù)在遷移時(shí),它的網(wǎng)絡(luò)地址常常會(huì)發(fā)生變化,此時(shí)如果想要做到自動(dòng)刷新,那就不得不修改WebHook的配置。
因此我們將方案一的架構(gòu)模式稍微改變一下

這時(shí)Spring Cloud Bus做配置更新步驟如下:
1、提交代碼觸發(fā)post請(qǐng)求給bus/refresh
2、server端接收到請(qǐng)求并發(fā)送給Spring Cloud Bus
3、Spring Cloud bus接到消息并通知給其它客戶端
4、其它客戶端接收到通知,請(qǐng)求Server端獲取最新配置
5、全部客戶端均獲取到最新的配置
下面我們就采用方案二來(lái)改造我們的工程,這樣的話我們?cè)趕erver端的代碼做一些改動(dòng),來(lái)支持bus/refresh
叁、改造服務(wù)端
- 改造上文的config的服務(wù)端子工程lovin-config-server,添加RabbitMQ的依賴。下面是改造后的主要的pom依賴:
<parent>
<artifactId>lovincloud</artifactId>
<groupId>com.eelve.lovincloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lovin-config-server</artifactId>
<packaging>jar</packaging>
<name>lovinconfigserver</name>
<version>0.0.1</version>
<description>配置服務(wù)端</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.1.6</version>
</dependency>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- 添加rabbitmq的連接配置
server:
port: 8886 # 服務(wù)端口號(hào)
spring:
application:
name: lovinconfigserver # 服務(wù)名稱
security:
basic:
enabled: true
user:
name: lovin
password: ${REGISTRY_SERVER_PASSWORD:lovin}
cloud:
config:
server:
git:
uri: https://github.com/lovinstudio/lovincloud
search-paths: lovin-config-repo
label: master
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
eureka:
client:
serviceUrl:
defaultZone: http://lovin:lovin@localhost:8881/eureka/ # 注冊(cè)到的eureka服務(wù)地址
肆、改造配置客戶端
- 改造上文的config的服務(wù)端子工程lovin-config-client,添加RabbitMQ的依賴。下面是改造后的主要的pom依賴:
<parent>
<artifactId>lovincloud</artifactId>
<groupId>com.eelve.lovincloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lovin-config-client</artifactId>
<packaging>jar</packaging>
<name>lovinconfigclient</name>
<version>0.0.1</version>
<description>配置消費(fèi)端</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.1.6</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-config-server</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.3.RELEASE</version>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- 添加連接rabbitmq的相關(guān)配置
- 修改bootstrap.yml添加連接rabbitmq的配置
server:
port: 8807 # 服務(wù)端口號(hào)
spring:
application:
name: lovinconfigclient # 服務(wù)名稱
security:
basic:
enabled: true
user:
name: lovin
password: ${REGISTRY_SERVER_PASSWORD:lovin}
#eureka:
# client:
# serviceUrl:
# defaultZone: http://lovin:lovin@localhost:8881/eureka/ # 注冊(cè)到的eureka服務(wù)地址
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
- 修改application.yml開啟消息跟蹤
spring:
cloud:
config:
name: lovin-config
profile: dev
#uri: http://localhost:8886/
#label: master
discovery:
enabled: true
service-id: lovinconfigserver
bus:
trace:
enabled: true
eureka:
client:
serviceUrl:
defaultZone: http://lovin:lovin@localhost:8881/eureka/ # 注意在高可用的時(shí)候需要見注冊(cè)中心配置移到該文件中,在application.yml中見會(huì)讀取不到配置
伍、啟動(dòng)測(cè)試
- 1.首先依次啟動(dòng)lovin-eureka-server、lovin-econfig-server、lovin-econfig-client
- 2.查看lovin-econfig-server查詢配置

- 3.查看lovin-econfig-client查詢配置

- 4.修改配置,并提交見token的值由lovin改為lovinupdate

- 5.再次查看lovin-econfig-server查詢配置

- 6.再次查看lovin-econfig-client查詢配置

- 7.刷新消息總線
由于api變更,url由老版本的/bus/refresh變?yōu)閍ctuator/bus-refresh

- 8.再次查看lovin-econfig-client查詢配置

我們可以看到已經(jīng)刷新成功,至此消息總線配置已經(jīng)完成
陸、局部刷新
某些場(chǎng)景下(例如灰度發(fā)布),我們可能只想刷新部分微服務(wù)的配置,此時(shí)可通過(guò)/actuator/bus-refresh端點(diǎn)的destination參數(shù)來(lái)定位要刷新的應(yīng)用程序。
- 例如:/actuator/bus-refresh?destination=customers:8000,這樣消息總線上的微服務(wù)實(shí)例就會(huì)根據(jù)destination參數(shù)的值來(lái)判斷是否需要要刷新。其中,customers:8000指的是各個(gè)微服務(wù)的ApplicationContext ID。destination參數(shù)也可以用來(lái)定位特定的微服務(wù)。
- 例如:/actuator/bus-refresh?destination=customers:**,這樣就可以觸發(fā)customers微服務(wù)所有實(shí)例的配置刷新。