引言mysql
近幾年傳統應用架構已經逐漸朝着微服務架構演進。那麼隨着業務的發展,微服務愈來愈龐大,此時服務配置的管理變得會複雜起來。爲了方便服務配置文件統一管理,實時更新,配置中心應運而生。其實,所謂配置中心,就是將配置的數據放在某種存儲介質中,該介質能夠是git
因爲咱們採用的是Spring-Boot的架構,所以當時天然而然會考慮到Spring-Cloud中提供的配置中心Spring-Cloud-Config,可是當時作完調研之後,以爲並不能直接用。所以,本文想來分享一下,原生Spring-Cloud-Config的配置中心的缺點,以及咱們對Spring-Cloud-Config作了哪些改動。spring
正文sql
OK,咱們當時作配置中心的選型的時候。第一選擇是Spring-Cloud- Config。Spring-Cloud-Config在存儲介質的選擇這塊,基本上網上全部的文章都在推薦使用Git,即將配置文件放在Git中,服務端從Git中讀取。其實官網上講的最詳細的配置,也是採起用Git做爲存儲介質。所以,我相信大部分讀者在生產上也是用Git做爲存儲介質,搭配Spring-Cloud-Config使用。可是呢,博主認爲以Git做爲存儲介質存在一些硬傷。數據庫
Git的權限管理是說控制用戶能不能Push或者Delete分支,或者能不能Push代碼,而不是能不能訪問某個目錄的文件。對目錄和文件的可讀是Git的最基本要求,不可能作到針對目錄級別的不可讀。所以若是直接使用,會出現這樣一種情形架構
因而,可能會有以下情形發生oracle
固然,你能夠禁止研發直接登錄Git改配置。而後呢,基於Git研發一套配置管理系統,在上面作權限控制,可是又有幾個公司這麼作呢?由於,這可能帶來第二個問題。異步
將配置信息放在Git中,有一個致命問題:粒度太粗了!nosql
你每次對一條配置發生crud的操做,其帶來的影響是整個文件發生變更。若是未來咱們須要對某條配置作灰度發佈,基於Git來作是比較麻煩的,注意了,我沒說不能作,只是比較麻煩。函數
那麼,當時咱們最理想的存儲介質就是數據庫,將配置信息放在數據庫裏有兩個好處
所以,咱們採用數據庫做爲存儲介質。慶幸的是,這一點在Spring-Cloud-Config中是支持的。在該組件下,只須要設置
spring.profiles.active=jdbc
就可以激活jdbc模式。
可是咱們很快發現了一個更大的問題,也正是由於這個問題,咱們不得以須要進行改寫Spring-Cloud-Config。
由於一個配置中心應該要可以作到,配置發生改動的時候,項目可以自動感知,自動更新配置纔對。在Spring-Cloud-Config中,這套機制是藉助一些代碼倉庫(SVN、Github等)提供的Webhook機制加上Spring-Cloud-Bus來實現的。
在Webhook中配置一個回調地址,刷新流程以下圖所示:
OK,那麼問題又來了!
(1)配置數據放在數據庫中,數據庫裏沒有Webhook這種東西啊,怎麼作到實時刷新?
(2)Spring-Cloud-Config的這套刷新機制依賴於消息總線,依賴於消息隊列,存在延遲的狀況!且依賴於消息隊列的可用性,系統的複雜度大大增長。若是生產環境上消息隊列出問題了,咱們的刷新功能就會受到影響!
因此,筆者認爲這套刷新機制並非很盡如人意,須要進行修改。所以,咱們很天然而然的想到了利用長輪詢來改寫Spring-Cloud-Config的刷新機制!
既然有長輪詢,那一定有短輪詢,我順便講講短輪詢是什麼!假設咱們有一個需求
那麼,若是採起短輪詢就是在客戶端(js)中不斷訪問後臺,後臺接到請求立刻返回最新的庫存數,而後刷新到這個頁面當中。
短輪詢的缺點?
很明顯資源浪費。假設有幾百人打開了該頁面,就有幾百個請求在不停的請求服務端,明顯聽着就不合理。
所以,天然就有了長輪詢的出現!其實也很簡單,客戶端(js)依然是不斷的去請求。可是呢,服務端不是立刻返回。而是等待庫存數量變化了再返回。你們知道,HTTP都有超時時間。若是在該時間內,依然沒有變化,客戶端將再次發起請求。
注意了,長短輪詢對於客戶端來講是沒有區別的,就是不斷的輪詢。可是對於服務端,區別就比較大了。在短輪詢狀況下,服務端對於每次請求無論有沒有變化都會當即返回結果。而長輪詢狀況下,若是有變化纔會當即返回結果。而若是沒有變化,服務端則不會再當即給客戶端返回結果,直到超時爲止。
那麼,咱們在項目中採用Spring的DeferredResult來實現。在Servlet3.0之後引入了異步請求以後,Spring封裝了一下提供了相應的支持,也就是DeferredResult,可以極大的提高吞吐量。
可能有人對Servlet的異步化不熟,我大概介紹一下。咱們平時經常使用的是同步Servlet,其執行流程以下圖所示:
缺點很明顯啦 ,業務邏輯線程和servlet容器線程是同一個,通常的業務邏輯總得發生點IO,好比查詢數據庫,好比產生RPC調用,這個時候就會發生阻塞,而咱們的servlet容器線程確定是有限的,當servlet容器線程都被阻塞的時候咱們的服務這個時候就會發生拒絕訪問,從而吞吐量上不去!
那麼,你使用異步Servlet以下圖所示
在異步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,改寫其中的刷新機制,更加符合咱們的業務場景!現已將改寫思路說清,你們能夠自行嘗試!
如何一塊兒學習,有沒有免費資料?
本文由博客一文多發平臺 OpenWrite 發佈!