1. 程式人生 > 程式設計 >為什麼不用原生的spring cloud config!

為什麼不用原生的spring cloud config!

引言

近幾年傳統應用架構已經逐漸朝著微服務架構演進。那麼隨著業務的發展,微服務越來越龐大,此時服務配置的管理變得會複雜起來。為了方便服務配置檔案統一管理,實時更新,配置中心應運而生。其實,所謂配置中心,就是將配置的資料放在某種儲存介質中,該介質可以是

  • File(例如Git、Svn)
  • Database(例如mysql、oracle)
  • nosql Database(例如Redis、Memacache、MongoDb)
  • 其他第三方中介軟體(例如Zookeeper)
    那麼配置中心可以簡單理解為是封裝了對這些介質進行操作的介面,供客戶端拉取使用。

由於我們採用的是Spring-Boot的架構,因此當時自然而然會考慮到Spring-Cloud中提供的配置中心Spring-Cloud-Config,但是當時做完調研以後,覺得並不能直接用。因此,本文想來分享一下,原生Spring-Cloud-Config的配置中心的缺點,以及我們對Spring-Cloud-Config做了哪些改動。

正文

OK,我們當時做配置中心的選型的時候。第一選擇是Spring-Cloud- Config。Spring-Cloud-Config在儲存介質的選擇這塊,基本上網上所有的文章都在推薦使用Git,即將配置檔案放在Git中,服務端從Git中讀取。其實官網上講的最詳細的配置,也是採取用Git作為儲存介質。因此,我相信大部分讀者在生產上也是用Git作為儲存介質,搭配Spring-Cloud-Config使用。但是呢,博主認為以Git作為儲存介質存在一些硬傷。

Git的許可權控制是個坑

Git的許可權管理是說控制使用者能不能Push或者Delete分支,或者能不能Push程式碼,而不是能不能訪問某個目錄的檔案。對目錄和檔案的可讀是Git的最基本要求,不可能做到針對目錄級別的不可讀。因此如果直接使用,會出現這樣一種情形

不同團隊之間可以互看對方配置!

於是,可能會有如下情形發生

A團隊同事A:"小B,這個地方不懂怎麼配?"

A團隊同事B:"去看看B團隊的配置,直接貼過來。"

然後B團隊就會發現自己的中介軟體裡總是會多出一些莫名奇妙的資料!

當然,你可以禁止研發直接登陸Git改配置。然後呢,基於Git研發一套配置管理系統,在上面做許可權控制,但是又有幾個公司這麼做呢?因為,這可能帶來第二個問題。

粒度問題

將配置資訊放在Git中,有一個致命問題:粒度太粗了!

你每次對一條配置發生crud的操作,其帶來的影響是整個檔案發生變動。如果將來我們需要對某條配置做灰度釋出,基於Git來做是比較麻煩的,注意了,我沒說不能做,只是比較麻煩。

那麼,當時我們最理想的儲存介質就是資料庫,將配置資訊放在資料庫裡有兩個好處

  • 基於資料庫開發一套配置管理系統,顯然比基於git來開發容易的多!
  • 將配置放在資料庫裡,每條配置對應資料庫的表中的一條記錄。這麼做粒度夠細,針對某些重要的配置,做灰度釋出,實現起來就容易很多。

因此,我們採用資料庫作為儲存介質。慶幸的是,這一點在Spring-Cloud-Config中是支援的。在該元件下,只需要設定

spring.profiles.active=jdbc

就能夠啟用jdbc模式。

但是我們很快發現了一個更大的問題,也正是因為這個問題,我們不得以需要進行改寫Spring-Cloud-Config。

Spring-Cloud-Config的重新整理機制是個坑!

因為一個配置中心應該要能夠做到,配置發生改動的時候,專案能夠自動感知,自動更新配置才對。在Spring-Cloud-Config中,這套機制是藉助一些程式碼倉庫(SVN、Github等)提供的Webhook機制加上Spring-Cloud-Bus來實現的。

在Webhook中配置一個回撥地址,重新整理流程如下圖所示:

file

OK,那麼問題又來了!

(1)配置資料放在資料庫中,資料庫裡沒有Webhook這種東西啊,怎麼做到實時重新整理?

(2)Spring-Cloud-Config的這套重新整理機制依賴於訊息匯流排,依賴於訊息佇列,存在延遲的情況!且依賴於訊息佇列的可用性,系統的複雜度大大增加。如果生產環境上訊息隊列出問題了,我們的重新整理功能就會受到影響!

所以,筆者認為這套重新整理機制並不是很盡如人意,需要進行修改。因此,我們很自然而然的想到了利用長輪詢來改寫Spring-Cloud-Config的重新整理機制!

長輪詢是什麼

既然有長輪詢,那必定有短輪詢,我順便講講短輪詢是什麼!假設我們有一個需求

在頁面上要實時顯示後臺的庫存數量!比如庫存減少了,使用者不需要進行重新整理,頁面上的數字自己會變化。

那麼,如果採取短輪詢就是在客戶端(js)中不斷訪問後臺,後臺接到請求馬上返回最新的庫存數,然後重新整理到這個頁面當中。

短輪詢的缺點?

很明顯資源浪費。假設有幾百人開啟了該頁面,就有幾百個請求在不停的請求服務端,明顯聽著就不合理。

因此,自然就有了長輪詢的出現!其實也很簡單,客戶端(js)依然是不斷的去請求。但是呢,服務端不是馬上返回。而是等待庫存數量變化了再返回。大家知道,HTTP都有超時時間。如果在該時間內,依然沒有變化,客戶端將再次發起請求。

注意了,長短輪詢對於客戶端來說是沒有區別的,就是不斷的輪詢。但是對於服務端,區別就比較大了。在短輪詢情況下,服務端對於每次請求不管有沒有變化都會立即返回結果。而長輪詢情況下,如果有變化才會立即返回結果。而如果沒有變化,服務端則不會再立即給客戶端返回結果,直到超時為止。 

怎麼實現

那麼,我們在專案中採用Spring的DeferredResult來實現。在Servlet3.0以後引入了非同步請求之後,Spring封裝了一下提供了相應的支援,也就是DeferredResult,能夠極大的提升吞吐量。

可能有人對Servlet的非同步化不熟,我大概介紹一下。我們平時常用的是同步Servlet,其執行流程如下圖所示:

file

缺點很明顯啦 ,業務邏輯執行緒和servlet容器執行緒是同一個,一般的業務邏輯總得發生點IO,比如查詢資料庫,比如產生RPC呼叫,這個時候就會發生阻塞,而我們的servlet容器執行緒肯定是有限的,當servlet容器執行緒都被阻塞的時候我們的服務這個時候就會發生拒絕訪問,從而吞吐量上不去!

那麼,你使用非同步Servlet如下圖所示

file

在非同步Servlet中,業務執行緒有自己的執行緒池進行處理,並不會佔用Tomcat中的執行緒,從而提升了吞吐量!

那麼,怎麼利用DeferredResult怎麼實現長輪詢呢?流程如下

(1)客戶端和服務端建立TCP連線

(2)客戶端發起HTTP請求

(3)服務端發起請求,監聽60s內是否有配置發生變動(如何監聽配置發生變動?)

(4)如果沒發生變動,給客戶端返回304標誌位,客戶端繼續發起請求

(5)如果發生了變動,服務端會呼叫DeferredResult.setResult返回200狀態碼,客戶端收到響應結果後,會發起請求獲取變更後的配置資訊。

最後一個問題:如何有效快速的監聽出配置表的資料發生了變動?

因為我們用的是mysql。這裡有一個Mysql的自定義函式叫mysql-udf-http。具有httpget()、httppost()、httpput()、httpdelete()四個函式,可以在MySQL資料庫中利用HTTP協議進行REST相關操作。然後再和mysql的觸發器結合起來用,可以實現在配置表發生變動的時候,主動通知我們的配置中心服務端。讓服務端明白配置發生了變動!

一個疑問

採用長輪詢技術來實現配置重新整理,客戶端和服務端需之間需要一直保持TCP連線進行通訊。可能有些朋友會擔心,到底服務端能撐多少的連線?可能覺得對效能有影響?

這裡給出參考配置

使用了記憶體8G、4核的虛擬機器器約可以撐8000左右的連線!

總結

最後這套配置中心,我基於原有的Spring-Cloud-Config,改寫其中的重新整理機制,更加符合我們的業務場景!現已將改寫思路說清,大家可以自行嘗試!

如何一起學習,有沒有免費資料?

file

本文由部落格一文多發平臺 OpenWrite 釋出!