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