天天看點

springcloud(九):配置中心和消息總線(配置中心終結版)

spring cloud bus通過輕量消息代理連接配接各個分布的節點。這會用在廣播狀态的變化(例如配置變化)或者其他的消息指令。spring bus的一個核心思想是通過分布式的啟動器對spring boot應用進行擴充,也可以用來建立一個多個應用之間的通信頻道。目前唯一實作的方式是用amqp消息代理作為通道,同樣特性的設定(有些取決于通道的設定)在更多通道的文檔中。

spring cloud bus被國内很多都翻譯為消息總線,也挺形象的。大家可以将它了解為管理和傳播所有分布式項目中的消息既可,其實本質是利用了mq的廣播機制在分布式的系統中傳播消息,目前常用的有kafka和rabbitmq。利用bus的機制可以做很多的事情,其中配置中心用戶端重新整理就是典型的應用場景之一,我們用一張圖來描述bus在配置中心使用的機制。

springcloud(九):配置中心和消息總線(配置中心終結版)

根據此圖我們可以看出利用spring cloud bus做配置更新的步驟:

1、送出代碼觸發post給用戶端a發送bus/refresh

2、用戶端a接收到請求從server端更新配置并且發送給spring cloud bus

3、spring cloud bus接到消息并通知給其它用戶端

4、其它用戶端接收到通知,請求server端擷取最新配置

5、全部用戶端均擷取到最新的配置

用戶端spring-cloud-config-client改造

需要多引入<code>spring-cloud-starter-bus-amqp</code>包,增加對消息總線的支援

配置檔案需要增加rebbitmq的相關配置,這樣用戶端代碼就改造完成了。

依次啟動spring-cloud-eureka、spring-cloud-config-server、spring-cloud-config-client項目,在啟動spring-cloud-config-client項目的時候我們會發現啟動日志會輸出這樣的一條記錄。

說明用戶端已經具備了消息總線通知的能力了,為了更好的模拟消息總線的效果,我們更改用戶端spring-cloud-config-client項目的端口為8003、8004依次啟動,這樣測試環境就準備好了。啟動後eureka背景效果圖如下:

springcloud(九):配置中心和消息總線(配置中心終結版)

我們先分别測試一下服務端和用戶端是否正确運作,通路:<code>http://localhost:8001/neo-config/dev</code>,傳回資訊:

說明server端都正常讀取到了配置資訊。

依次通路:<code>http://localhost:8002/hello</code>、<code>http://localhost:8003/hello</code>、<code>http://localhost:8004/hello</code>,傳回:<code>hello im dev</code>。說明用戶端都已經讀取到了server端的内容。

現在我們更新<code>neo-config-dev.properties</code> 中<code>neo.hello</code>的值為<code>hello im dev update</code>并送出到代碼庫中,通路:<code>http://localhost:8002/hello</code> 依然傳回<code>hello im dev</code>。我們對端口為8002的用戶端發送一個<code>/bus/refresh</code>的post請求。在win下使用下面指令來模拟webhook.

執行完成後,依次通路:<code>http://localhost:8002/hello</code>、<code>http://localhost:8003/hello</code>、<code>http://localhost:8004/hello</code>,傳回:<code>hello im dev update</code>。說明三個用戶端均已經拿到了最新配置檔案的資訊,這樣我們就實作了圖一中的示例。

在上面的流程中,我們已經到達了利用消息總線觸發一個用戶端<code>bus/refresh</code>,而重新整理所有用戶端的配置的目的。但這種方式并不優雅。原因如下:

打破了微服務的職責單一性。微服務本身是業務子產品,它本不應該承擔配置重新整理的職責。

破壞了微服務各節點的對等性。

有一定的局限性。例如,微服務在遷移時,它的網絡位址常常會發生變化,此時如果想要做到自動重新整理,那就不得不修改webhook的配置。

是以我們将上面的架構模式稍微改變一下

springcloud(九):配置中心和消息總線(配置中心終結版)

這時spring cloud bus做配置更新步驟如下:

1、送出代碼觸發post請求給bus/refresh

2、server端接收到請求并發送給spring cloud bus

這樣的話我們在server端的代碼做一些改動,來支援<code>bus/refresh</code>

配置檔案增加rebbitmq的相關配置,關閉安全驗證。這樣server端代碼就改造完成了。

依次啟動spring-cloud-eureka、spring-cloud-config-server、spring-cloud-config-client項目,改動spring-cloud-config-client項目端口為8003、8004依次啟動。測試環境準備完成。

按照上面的測試方式,通路server端和三個用戶端測試均可以正确傳回資訊。同樣修改<code>neo-config-dev.properties</code> 中<code>neo.hello</code>的值為<code>hello im dev update</code>并送出到代碼庫中。在win下使用下面指令來模拟webhook觸發server端<code>bus/refresh</code>.

執行完成後,依次通路:<code>http://localhost:8002/hello</code>、<code>http://localhost:8003/hello</code>、<code>http://localhost:8004/hello</code>,傳回:<code>hello im dev update</code>。說明三個用戶端均已經拿到了最新配置檔案的資訊,這樣我們就實作了上圖中的示例。

某些場景下(例如灰階釋出),我們可能隻想重新整理部分微服務的配置,此時可通過<code>/bus/refresh</code>端點的destination參數來定位要重新整理的應用程式。

例如:<code>/bus/refresh?destination=customers:8000</code>,這樣消息總線上的微服務執行個體就會根據destination參數的值來判斷是否需要要重新整理。其中,<code>customers:8000</code>指的是各個微服務的applicationcontext id。

destination參數也可以用來定位特定的微服務。例如:<code>/bus/refresh?destination=customers:**</code>,這樣就可以觸發customers微服務所有執行個體的配置重新整理。

一些場景下,我們可能希望知道spring cloud bus事件傳播的細節。此時,我們可以跟蹤總線事件(remoteapplicationevent的子類都是總線事件)。

跟蹤總線事件非常簡單,隻需設定<code>spring.cloud.bus.trace.enabled=true</code>,這樣在<code>/bus/refresh</code>端點被請求後,通路<code>/trace</code>端點就可獲得類似如下的結果:

這個日志顯示了<code>customers:8001</code>發出了refreshremoteapplicationevent事件,廣播給所有的服務,被<code>customers:9000</code>和<code>stores:8081</code>接受到了。想要對接受到的消息自定義自己的處理方式的話,可以添加<code>@eventlistener</code>注解的ackremoteapplicationevent和sentapplicationevent類型到你自己的應用中。或者到tracerepository類中,直接處理資料。

這樣,我們就可清晰地知道事件的傳播細節。

<code>/bus/refresh</code> 有一個很嚴重的bug,一直沒有解決:對用戶端執行<code>/bus/refresh</code>之後,挂到總線的上的用戶端都會從eureka注冊中心撤銷登記;如果對server端執行<code>/bus/refresh</code>,server端也會從eureka注冊中心撤銷登記。再用白話解釋一下,就是本來人家在eureka注冊中心注冊的好好的,隻要你對着它執行一次<code>/bus/refresh</code>,立刻就會從euraka中挂掉。

其實這個問題挺嚴重的,本來你利用<code>/bus/refresh</code>給所有的節點來更新配置資訊呢,結果把服務從euraka中給搞掉了,那麼如果别人需要調用用戶端的服務的時候就直接歇菜了。不知道國内有童鞋公司在生産中用到這個功能沒有,用了不就很慘烈。在網上搜尋了一下,國内網友和國外網友都遇到過很多次,但是一直沒有解決,很幸運就是我在寫這篇文章的前三天,netflix修複了這個問題,使用spring cloud最新版本的包就可以解決這個問題。由此也可以發現spring cloud還在快速的發展中,最新的版本可能也會有一些不穩定性,可見路漫漫而修遠兮。

在pom中使用spring cloud的版本,解決這個bug.

主要是這句:<code>&lt;spring-cloud.version&gt;dalston.sr1&lt;/spring-cloud.version&gt;</code> ,詳情可以參考本文示例中的代碼

bug的讨論和解決過程可以看github上面這兩個issue:

<a href="https://github.com/spring-cloud/spring-cloud-config/issues/692">/bus/refresh causes instances registered in eureka server disappeared #692</a>

<a href="https://github.com/spring-cloud/spring-cloud-netflix/issues/1857">making post on ‘refresh’ permamently deregisters the service from eureka #1857</a>

參考:

<a href="http://www.itmuch.com/spring-cloud/spring-cloud-bus-auto-refresh-configuration/">config server——使用spring cloud bus自動重新整理配置</a>

<a href="http://blog.didispace.com/springcloud7/">spring cloud建構微服務架構(七)消息總線</a>

<a href="https://github.com/ityouknow/spring-cloud-starter">示例代碼</a>

作者:純潔的微笑

版權歸作者所有,轉載請注明出處