springcloud(九):配置中心和消息总线(配置中心终结版)
我們?cè)趕pringcloud(七):配置中心svn示例和refresh中講到,如果需要客戶端獲取到最新的配置信息需要執(zhí)行refresh,我們可以利用webhook的機(jī)制每次提交代碼發(fā)送請(qǐng)求來刷新客戶端,當(dāng)客戶端越來越多的時(shí)候,需要每個(gè)客戶端都執(zhí)行一遍,這種方案就不太適合了。使用Spring Cloud Bus可以完美解決這一問題。
Spring Cloud Bus
Spring cloud bus通過輕量消息代理連接各個(gè)分布的節(jié)點(diǎn)。這會(huì)用在廣播狀態(tài)的變化(例如配置變化)或者其他的消息指令。Spring bus的一個(gè)核心思想是通過分布式的啟動(dòng)器對(duì)spring boot應(yīng)用進(jìn)行擴(kuò)展,也可以用來建立一個(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)景之一,我們用一張圖來描述bus在配置中心使用的機(jī)制。
根據(jù)此圖我們可以看出利用Spring Cloud Bus做配置更新的步驟:
- 1、提交代碼觸發(fā)post給客戶端A發(fā)送bus/refresh
- 2、客戶端A接收到請(qǐng)求從Server端更新配置并且發(fā)送給Spring Cloud Bus
- 3、Spring Cloud bus接到消息并通知給其它客戶端
- 4、其它客戶端接收到通知,請(qǐng)求Server端獲取最新配置
- 5、全部客戶端均獲取到最新的配置
項(xiàng)目示例
我們選擇上一篇文章springcloud(八):配置中心服務(wù)化和高可用版本的示例代碼來改造,MQ我們使用RabbitMQ來做示例。
客戶端spring-cloud-config-client改造
1、添加依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>?
需要多引入spring-cloud-starter-bus-amqp包,增加對(duì)消息總線的支持
2、配置文件
## 刷新時(shí),關(guān)閉安全驗(yàn)證 management.security.enabled=false ## 開啟消息跟蹤 spring.cloud.bus.trace.enabled=truespring.rabbitmq.host=192.168.9.89 spring.rabbitmq.port=5672 spring.rabbitmq.username=admin spring.rabbitmq.password=123456?
配置文件需要增加RebbitMq的相關(guān)配置,這樣客戶端代碼就改造完成了。
3、測(cè)試
依次啟動(dòng)spring-cloud-eureka、spring-cloud-config-server、spring-cloud-config-client項(xiàng)目,在啟動(dòng)spring-cloud-config-client項(xiàng)目的時(shí)候我們會(huì)發(fā)現(xiàn)啟動(dòng)日志會(huì)輸出這樣的一條記錄。
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)說明客戶端已經(jīng)具備了消息總線通知的能力了,為了更好的模擬消息總線的效果,我們更改客戶端spring-cloud-config-client項(xiàng)目的端口為8003、8004依次啟動(dòng),這樣測(cè)試環(huán)境就準(zhǔn)備好了。啟動(dòng)后eureka后臺(tái)效果圖如下:
我們先分別測(cè)試一下服務(wù)端和客戶端是否正確運(yùn)行,訪問: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。說明客戶端都已經(jīng)讀取到了server端的內(nèi)容。
現(xiàn)在我們更新neo-config-dev.properties?中neo.hello的值為hello im dev update并提交到代碼庫(kù)中,訪問:http://localhost:8002/hello?依然返回hello im dev。我們對(duì)端口為8002的客戶端發(fā)送一個(gè)/bus/refresh的post請(qǐng)求。在win下使用下面命令來模擬webhook.
curl -X POST http://localhost:8002/bus/refresh執(zhí)行完成后,依次訪問:http://localhost:8002/hello、http://localhost:8003/hello、http://localhost:8004/hello,返回:hello im dev update。說明三個(gè)客戶端均已經(jīng)拿到了最新配置文件的信息,這樣我們就實(shí)現(xiàn)了圖一中的示例。
改進(jìn)版本
在上面的流程中,我們已經(jīng)到達(dá)了利用消息總線觸發(fā)一個(gè)客戶端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、全部客戶端均獲取到最新的配置
這樣的話我們?cè)趕erver端的代碼做一些改動(dòng),來支持bus/refresh
1、添加依賴
<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包,增加對(duì)消息總線的支持
2、配置文件
server:port: 8001 spring:application:name: spring-cloud-config-servercloud:config:server:git:uri: https://github.com/ityouknow/spring-cloud-starter/ # 配置git倉(cāng)庫(kù)的地址search-paths: config-repo # git倉(cāng)庫(kù)地址下的相對(duì)地址,可以配置多個(gè),用,分割。username: username # git倉(cāng)庫(kù)的賬號(hào)password: password # git倉(cāng)庫(kù)的密碼rabbitmq:host: 192.168.0.6port: 5672username: adminpassword: 123456eureka:client:serviceUrl:defaultZone: http://localhost:8000/eureka/ ## 注冊(cè)中心eurka地址 management:security:enabled: false?
配置文件增加RebbitMq的相關(guān)配置,關(guān)閉安全驗(yàn)證。這樣server端代碼就改造完成了。
3、測(cè)試
依次啟動(dòng)spring-cloud-eureka、spring-cloud-config-server、spring-cloud-config-client項(xiàng)目,改動(dòng)spring-cloud-config-client項(xiàng)目端口為8003、8004依次啟動(dòng)。測(cè)試環(huán)境準(zhǔn)備完成。
按照上面的測(cè)試方式,訪問server端和三個(gè)客戶端測(cè)試均可以正確返回信息。同樣修改neo-config-dev.properties中neo.hello的值為hello im dev update并提交到代碼庫(kù)中。在win下使用下面命令來模擬webhook觸發(fā)server端bus/refresh.
curl -X POST http://localhost:8001/bus/refresh執(zhí)行完成后,依次訪問:http://localhost:8002/hello、http://localhost:8003/hello、http://localhost:8004/hello,返回:hello im dev update。說明三個(gè)客戶端均已經(jīng)拿到了最新配置文件的信息,這樣我們就實(shí)現(xiàn)了上圖中的示例。
其它
局部刷新
某些場(chǎng)景下(例如灰度發(fā)布),我們可能只想刷新部分微服務(wù)的配置,此時(shí)可通過/bus/refresh端點(diǎn)的destination參數(shù)來定位要刷新的應(yīng)用程序。
例如:/bus/refresh?destination=customers:8000,這樣消息總線上的微服務(wù)實(shí)例就會(huì)根據(jù)destination參數(shù)的值來判斷是否需要要刷新。其中,customers:8000指的是各個(gè)微服務(wù)的ApplicationContext ID。
destination參數(shù)也可以用來定位特定的微服務(wù)。例如:/bus/refresh?destination=customers:**,這樣就可以觸發(fā)customers微服務(wù)所有實(shí)例的配置刷新。
跟蹤總線事件
一些場(chǎng)景下,我們可能希望知道Spring Cloud Bus事件傳播的細(xì)節(jié)。此時(shí),我們可以跟蹤總線事件(RemoteApplicationEvent的子類都是總線事件)。
跟蹤總線事件非常簡(jiǎn)單,只需設(shè)置spring.cloud.bus.trace.enabled=true,這樣在/bus/refresh端點(diǎn)被請(qǐng)求后,訪問/trace端點(diǎn)就可獲得類似如下的結(jié)果:
{"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": "*:**"} }?
這個(gè)日志顯示了customers:8001發(fā)出了RefreshRemoteApplicationEvent事件,廣播給所有的服務(wù),被customers:9000和stores:8081接受到了。想要對(duì)接受到的消息自定義自己的處理方式的話,可以添加@EventListener注解的AckRemoteApplicationEvent和SentApplicationEvent類型到你自己的應(yīng)用中。或者到TraceRepository類中,直接處理數(shù)據(jù)。
這樣,我們就可清晰地知道事件的傳播細(xì)節(jié)。
/bus/refresh?BUG
/bus/refresh?有一個(gè)很嚴(yán)重的BUG,一直沒有解決:對(duì)客戶端執(zhí)行/bus/refresh之后,掛到總線的上的客戶端都會(huì)從Eureka注冊(cè)中心撤銷登記;如果對(duì)server端執(zhí)行/bus/refresh,server端也會(huì)從Eureka注冊(cè)中心撤銷登記。再用白話解釋一下,就是本來人家在Eureka注冊(cè)中心注冊(cè)的好好的,只要你對(duì)著它執(zhí)行一次/bus/refresh,立刻就會(huì)從Euraka中掛掉。
其實(shí)這個(gè)問題挺嚴(yán)重的,本來你利用/bus/refresh給所有的節(jié)點(diǎn)來更新配置信息呢,結(jié)果把服務(wù)從Euraka中給搞掉了,那么如果別人需要調(diào)用客戶端的服務(wù)的時(shí)候就直接歇菜了。不知道國(guó)內(nèi)有童鞋公司在生產(chǎn)中用到這個(gè)功能沒有,用了不就很慘烈。在網(wǎng)上搜索了一下,國(guó)內(nèi)網(wǎng)友和國(guó)外網(wǎng)友都遇到過很多次,但是一直沒有解決,很幸運(yùn)就是我在寫這篇文章的前三天,Netflix修復(fù)了這個(gè)問題,使用Spring Cloud最新版本的包就可以解決這個(gè)問題。由此也可以發(fā)現(xiàn)Spring Cloud還在快速的發(fā)展中,最新的版本可能也會(huì)有一些不穩(wěn)定性,可見路漫漫而修遠(yuǎn)兮。
在pom中使用Spring Cloud的版本,解決這個(gè)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上面這兩個(gè)issue:
- /bus/refresh causes instances registered in Eureka Server disappeared #692
- Making POST on ‘refresh’ permamently deregisters the service from Eureka #1857
參考:
Config Server——使用Spring Cloud Bus自動(dòng)刷新配置
Spring Cloud構(gòu)建微服務(wù)架構(gòu)(七)消息總線
示例代碼-github
示例代碼-碼云
作者:純潔的微笑
出處:http://www.ityouknow.com/?
版權(quán)歸作者所有,轉(zhuǎn)載請(qǐng)注明出處
轉(zhuǎn)載于:https://www.cnblogs.com/powerwu/articles/9745343.html
總結(jié)
以上是生活随笔為你收集整理的springcloud(九):配置中心和消息总线(配置中心终结版)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 记录知识点或技术方案信息
- 下一篇: U盘启动盘还原