微信公衆號:內核小王子 關注可瞭解更多關於數據庫,JVM內核相關的知識; 若是你有任何疑問也能夠加我pigpdong[^1]java
平常開發中咱們的應用中通常都會有數據庫相關的配置,redis相關的配置,log4j相關的配置 等經常使用配置,這些咱們稱爲靜態配置,在應用啓動的時候就須要加載,修改配置須要重啓應用,這類配置通常是針對相關資源的訪問地址和訪問權限,還有一類配置和業務密切相關,應用在運行過程當中須要監聽這些配置的變化以方便修改運行模式或者響應對應的策略,例如併發控制數,業務開關等,能夠用來作服務降級和限流,例如在數據庫新老表作遷移的時候,咱們能夠用來配置進行動態切換模式:同步雙寫讀老表,同步雙寫讀新表,寫新表讀新表。若是這些配置不能進行集中式管理,那麼當咱們的服務部署有成千上萬的實例後,即便藉助ansible這些運維工具,那麼修改配置也將是一件超級麻煩並且極容易出錯的事情,在作發佈的時候也不在敏捷。node
因此,微服務架構下,咱們須要一個集中式的配置管理系統,那麼這個系統須要提供哪些功能才能解決上面的問題呢nginx
1.權限控制,固然不能全部的人均可以修改配置,若是可以繼承公司的SSO或者LDAP固然更好redis
2.審計日誌,全部的修改須要記錄操做日誌,方便後續出現異議可以找到對應的操做人,也能夠提供審批流程spring
3.環境管理,開發,測試,生成環境下的配置確定要作隔離,相同group內的配置可能大多相同,例如同一個IDC機房的應用也能夠有namespace作區分數據庫
4.配置回滾,當發現配置錯誤,或者在該配置下程序發生異常能夠當即回滾到以前的版本,這須要該系統可以有版本管理的功能api
5.灰度發佈,有時候咱們新上線一個功能,想先經過少部分流量測試下,這個時候咱們能夠隨機只修改部分應用的配置,當測試正常後在推送到全部的應用緩存
6.高可用,配置中心須要高可用,因此最好能支持集羣部署,同時配置中心繫統掛了以後最好能不影響應用,應用可以繼續使用本地緩存的配置安全
7.配置中心,應該可以在配置發生變動後實時通知到應用,應用端多是一個監聽器,配置也可能就是一個普通bean裏面的屬性,須要自動監聽到變化並進行調整微信
目前已經開源的集中式配置管理中間件裏面有攜程的apollo和百度的disconf,已經阿里的diamond和spring cloud生態下地config系統,下面咱們主要分析下disconf和apollo的實現
disconf提供一個客戶端程序集成在應用程序內方便應用去遠程獲取配置,並監聽配置的變化,服務端提供配置的新增和修改,並給客戶端提供獲取配置的api
其中客戶端有如下幾個模塊
scan模塊
掃描全部的disconf註解,註解有兩種,一張是標示這個bean是一個配置能夠和具體的配置文件作管理,bean裏面的屬性就是配置文件裏面的key-value,當服務端配置修改後,這個bean會自動經過反射調用對應屬性的set方法,將這個bean裏面屬性的value值變動爲最新的配置的值,另外一個註解是標示這是一個配置監聽器,當配置變動後,會調用監聽器裏的方法,當有業務須要關聯到配置變化進行改變策略的時候能夠加上這種註解
store模塊
將從遠程服務端拉取到的配置文件存儲到本地,store模塊有一個後臺線程會按期掃描存儲在本地的配置文件是否有變化,若是有變化就會通知scan模塊掃描到得javabean和對應的監聽器
fetch模塊
當watch模塊監控到節點變化後,經過http調用遠程restful接口,獲取最新配置,而後調用store模塊存儲
watch模塊
監控zookeeper上node的變更,當有變化後會會調用fetch模塊獲取配置,服務端在作配置修改的時候會將ZOOKEEPER裏面相關的臨時節點刪除,而後全部watch該node的應用都會收到通知,全部須要監聽配置變化的應用都須要和zookeeper維護一個長鏈接
disconf的高可用保證:server端只是提供了配置的管理以及提供接口供客戶端經過http獲取, 因此server端是無狀態的
相比於disconf長期沒有維護,並且只提供了較爲簡單的分組管理功能,apollo社區目前比較活躍,並且功能更爲完善,不只僅提供了權限審計等安全措施,還提供了灰度發佈,版本回滾等,在高可用方面將服務拆分了3個獨立的模塊,每一個模塊均可以獨立集羣化部署,也不用依賴zookeeper,並且有不少大公司作背書。不過disconf部署簡單,而apollo就複雜的多
和應用端集成, 監聽配置變化,獲取最新配置
提供獲取配置的接口供客戶端使用以及當有新配置更新時會通知客戶端,客戶端能夠以必定週期定時從ConfigService獲取最新配置,configservice和客戶端維護一個長鏈接,當有配置更新的時候,會經過長鏈接通知客戶端去取最新配置
提供配置管理的接口供portal管理頁面使用,例如配置的修改和發佈 AdminService和ConfigService共用一個數據庫,adminService每次發佈配置的時候都會往releasemessage表裏面插入一條記錄,而configService會掃描這張表看是否有新插入數據,若是有變化就會通知客戶端
提供登錄和審計日誌的功能,提供http接口給管理界面,portal須要經過rpc調用AdminService提供的配置管理的接口,portal有本身的數據庫
咱們能夠從兩條線來看這個架構
是springcloud生態下一個服務註冊和發現的插件,configService是集羣部署的,並且是須要作負載均衡的,不能全部的客戶端都和同一個configservice維護長鏈接,那麼當客戶端應用繼續增加的時候,configservice也能夠橫向擴展來支撐,那麼如何作到configservice在擴展的時候對應用無感呢,須要一個註冊中心來作服務發現的功能,因此configservice會在啓動和下線的時候通知註冊中心,而客戶端只須要去註冊中心獲取最新的configservice列表,讓後選擇一個就行了,而AdminService和potal之間存在rpc調用,而AdminService也是無狀態而且集羣化部署的,那麼portal也能夠經過註冊中心去坐負載均衡,在其中一個AdminService節點掛了以後能夠選其餘的節點繼續使用, 因此部署一套Eureka能夠同時給configService和客戶端,portal和adminService同時使用
這個服務主要是封裝了Eureka的API,至關於Eureka的代理,這個服務主要是由於Eureka只有java的api作服務發現,若是應用要使用apollo便須要在客戶端經過Eureka的java api獲取adminservice的服務列表,而其餘語言環境就沒有辦法了,因此MetaService提供了一個http接口供client和potal使用,客戶端經過http請求MetaService就能夠獲取到AdminService得地址
因爲上面的MetaService也是集羣化部署的,那麼client和portal怎麼知道MetaService的地址呢,能夠在nginx上配置一個域名,在nginx上作負載均衡轉發到對應的metaservice, 而portal也是集羣部署的,配置管理人員也須要經過域名訪問nginx,在轉發到對應的portal
因此portal節點和metaservice節點的增長和刪除都須要在nginx上作對應的更改,而configService和AdminService則的彈性擴容則不須要