配置中心發(fā)展背景
隨著程序功能的日益復(fù)雜优质,程序的配置日益增多:
各種功能的開關(guān)末患、參數(shù)的配置牲证、服務(wù)器的地址……
對程序配置的期望值也越來越高:
配置修改后實(shí)時(shí)生效哮针,灰度發(fā)布,分環(huán)境坦袍、分集群管理配置十厢,完善的權(quán)限、審核機(jī)制……
在這樣的大環(huán)境下捂齐,傳統(tǒng)的通過配置文件蛮放、數(shù)據(jù)庫等方式已經(jīng)越來越無法滿足開發(fā)人員對配置管理的需求。
本篇主要圍繞 Apollo分布式配置中心 這一主流組件展開討論奠宜。
一包颁、Apollo 總體設(shè)計(jì)
1.1 Apollo 總體設(shè)計(jì)圖
上圖簡要描述了Apollo的總體設(shè)計(jì)瞻想,自下而上看:
- Config Service 提供配置的讀取、推送等功能娩嚼,服務(wù)對象是Apollo客戶端
- Admin Service 提供配置的修改蘑险、發(fā)布等功能,服務(wù)對象是Apollo Portal(管理界面)
- Config Service 和 Admin Service 都是多實(shí)例岳悟、無狀態(tài)部署佃迄,所以需要將自己注冊到 Eureka 中并保持心跳
- 在Eureka之上架了一層 Meta Server 用于封裝 Eureka 的服務(wù)發(fā)現(xiàn)接口
- Client 通過域名訪問 Meta Server 獲取 Config Service 服務(wù)列表(IP+Port),而后直接通過 IP+Port 訪問服務(wù)贵少,同時(shí)在 Client 側(cè)會做 load balance呵俏、錯誤重試
- Portal 通過域名訪問 Meta Server 獲取 Admin Service 服務(wù)列表(IP+Port),而后直接通過 IP+Port 訪問服務(wù)春瞬,同時(shí)在 Portal 側(cè)會做 load balance、錯誤重試
- 為了簡化部署套啤,實(shí)際上會把 Config Service宽气、Eureka 和 Meta Server 三個邏輯角色部署在同一個JVM進(jìn)程中
1.2 各模塊簡介
Config Service
- 提供配置獲取接口
- 提供配置更新推送接口(基于Http long polling)
- 服務(wù)端使用Spring DeferredResult實(shí)現(xiàn)異步化,從而大大增加長連接數(shù)量
- 目前使用的tomcat embed默認(rèn)配置是最多10000個連接(可以調(diào)整)潜沦,使用了4C8G的虛擬機(jī)實(shí)測可以支撐10000個連接萄涯,所以滿足需求(一個應(yīng)用實(shí)例只會發(fā)起一個長連接)。
- 接口服務(wù)對象為Apollo客戶端
Admin Service
- 提供配置管理接口
- 提供配置修改唆鸡、發(fā)布等接口
- 接口服務(wù)對象為Portal
Meta Server
- Portal通過域名訪問Meta Server獲取Admin Service服務(wù)列表(IP+Port)
- Client通過域名訪問Meta Server獲取Config Service服務(wù)列表(IP+Port)
- Meta Server從Eureka獲取Config Service和Admin Service的服務(wù)信息涝影,相當(dāng)于是一個Eureka Client
- 增設(shè)一個Meta Server的角色主要是為了封裝服務(wù)發(fā)現(xiàn)的細(xì)節(jié),對Portal和Client而言争占,永遠(yuǎn)通過一個Http接口獲取Admin Service和Config Service的服務(wù)信息燃逻,而不需要關(guān)心背后實(shí)際的服務(wù)注冊和發(fā)現(xiàn)組件
- Meta Server只是一個邏輯角色,在部署時(shí)和Config Service是在一個JVM進(jìn)程中的臂痕,所以IP伯襟、端口和Config Service一致
Eureka
- 基于Eureka和Spring Cloud Netflix提供服務(wù)注冊和發(fā)現(xiàn)
- Config Service和Admin Service會向Eureka注冊服務(wù),并保持心跳
- 為了簡單起見握童,目前Eureka在部署時(shí)和Config Service是在一個JVM進(jìn)程中的(通過Spring Cloud Netflix)
Portal
- 提供Web界面供用戶管理配置
- 通過Meta Server獲取Admin Service服務(wù)列表(IP+Port)姆怪,通過IP+Port訪問服務(wù)
- 在Portal側(cè)做load balance、錯誤重試
Client
- Apollo提供的客戶端程序澡绩,為應(yīng)用提供配置獲取稽揭、實(shí)時(shí)更新等功能
- 通過Meta Server獲取Config Service服務(wù)列表(IP+Port),通過IP+Port訪問服務(wù)
- 在Client側(cè)做load balance肥卡、錯誤重試
二溪掀、Apollo客戶端設(shè)計(jì)
上圖簡要描述了Apollo客戶端的實(shí)現(xiàn)原理:
- 客戶端和服務(wù)端保持了一個長連接,從而能第一時(shí)間獲得配置更新的推送步鉴。(通過Http Long Polling實(shí)現(xiàn))
- 客戶端還會定時(shí)從Apollo配置中心服務(wù)端拉取應(yīng)用的最新配置膨桥。
- 這是一個fallback機(jī)制蛮浑,為了防止推送機(jī)制失效導(dǎo)致配置不更新
- 客戶端定時(shí)拉取會上報(bào)本地版本,所以一般情況下只嚣,對于定時(shí)拉取的操作沮稚,服務(wù)端都會返回304 - Not Modified
- 定時(shí)頻率默認(rèn)為每5分鐘拉取一次,客戶端也可以通過在運(yùn)行時(shí)指定System Property: apollo.refreshInterval來覆蓋册舞,單位為分鐘蕴掏。
- 客戶端從Apollo配置中心服務(wù)端獲取到應(yīng)用的最新配置后,會保存在內(nèi)存中
- 客戶端會把從服務(wù)端獲取到的配置在本地文件系統(tǒng)緩存一份
- 在遇到服務(wù)不可用调鲸,或網(wǎng)絡(luò)不通的時(shí)候盛杰,依然能從本地恢復(fù)配置
- 應(yīng)用程序從Apollo客戶端獲取最新的配置、訂閱配置更新通知
三藐石、配置更新推送實(shí)現(xiàn)
3.1 配置發(fā)送后的實(shí)時(shí)推送設(shè)計(jì)
上圖簡要描述了配置發(fā)布的大致過程:
- 用戶在Portal操作配置發(fā)布
- Portal調(diào)用Admin Service的接口操作發(fā)布
- Admin Service發(fā)布配置后即供,發(fā)送ReleaseMessage給各個Config Service
- Config Service收到ReleaseMessage后,通知對應(yīng)的客戶端
之前提到了Apollo客戶端和服務(wù)端保持了一個長連接于微,從而能第一時(shí)間獲得配置更新的推送逗嫡。長連接實(shí)際上是通過Http Long Polling實(shí)現(xiàn)的,具體而言:
- 客戶端發(fā)起一個Http請求到服務(wù)端
- 服務(wù)端會保持住這個連接60秒
- 如果在60秒內(nèi)有客戶端關(guān)心的配置變化株依,被保持住的客戶端請求會立即返回驱证,并告知客戶端有配置變化的namespace信息,客戶端會據(jù)此拉取對應(yīng)namespace的最新配置
- 如果在60秒內(nèi)沒有客戶端關(guān)心的配置變化恋腕,那么會返回Http狀態(tài)碼304給客戶端
- 客戶端在收到服務(wù)端請求后會立即重新發(fā)起連接抹锄,回到第一步
考慮到會有數(shù)萬客戶端向服務(wù)端發(fā)起長連,在服務(wù)端使用了async servlet(Spring DeferredResult)來服務(wù)Http Long Polling請求荠藤。
注:DeferredResult可以允許容器線程快速釋放以便接受更多的請求提升吞吐量伙单,讓真正的業(yè)務(wù)邏輯在其他的工作線程中完成。
3.2 發(fā)送ReleaseMessage的實(shí)現(xiàn)方式
Admin Service在配置發(fā)布后哈肖,需要通知所有的Config Service有配置發(fā)布车份,從而Config Service可以通知對應(yīng)的客戶端來拉取最新的配置。
從概念上來看牡彻,這是一個典型的消息使用場景扫沼,Admin Service作為producer發(fā)出消息,各個Config Service作為consumer消費(fèi)消息庄吼。通過一個消息組件(Message Queue)就能很好的實(shí)現(xiàn)Admin Service和Config Service的解耦缎除。
在實(shí)現(xiàn)上,考慮到Apollo的實(shí)際使用場景总寻,以及為了盡可能減少外部依賴器罐,Apollo沒有采用外部的消息中間件,而是通過數(shù)據(jù)庫實(shí)現(xiàn)了一個簡單的消息隊(duì)列渐行。
實(shí)現(xiàn)方式如下:
- Admin Service在配置發(fā)布后會往ReleaseMessage表插入一條消息記錄轰坊,消息內(nèi)容就是配置發(fā)布的AppId+Cluster+Namespace铸董,參見DatabaseMessageSender
- Config Service有一個線程會每秒掃描一次ReleaseMessage表,看看是否有新的消息記錄肴沫,參見ReleaseMessageScanner
- Config Service如果發(fā)現(xiàn)有新的消息記錄粟害,那么就會通知到所有的消息監(jiān)聽器(ReleaseMessageListener),如NotificationControllerV2颤芬,消息監(jiān)聽器的注冊過程參見ConfigServiceAutoConfiguration
- NotificationControllerV2得到配置發(fā)布的AppId+Cluster+Namespace后悲幅,會通知對應(yīng)的客戶端
示意圖如下:
3.3 Config Service通知客戶端的實(shí)現(xiàn)方式
上一節(jié)中簡要描述了NotificationControllerV2是如何得知有配置發(fā)布的,那NotificationControllerV2在得知有配置發(fā)布后是如何通知到客戶端的呢站蝠?
實(shí)現(xiàn)方式如下:
- 客戶端會發(fā)起一個Http請求到Config Service的notifications/v2接口汰具,也就是NotificationControllerV2则涯,參見RemoteConfigLongPollService
- NotificationControllerV2不會立即返回結(jié)果袜硫,而是通過Spring DeferredResult把請求掛起
- 如果在60秒內(nèi)沒有該客戶端關(guān)心的配置發(fā)布,那么會返回Http狀態(tài)碼304給客戶端
- 如果有該客戶端關(guān)心的配置發(fā)布讨阻,NotificationControllerV2會調(diào)用DeferredResult的setResult方法澜倦,傳入有配置變化的namespace信息聚蝶,同時(shí)該請求會立即返回》事。客戶端從返回的結(jié)果中獲取到配置變化的namespace后既荚,會立即請求Config Service獲取該namespace的最新配置稚失。
四栋艳、可用性考慮
配置中心作為基礎(chǔ)服務(wù),可用性要求非常高句各,下面的表格描述了不同場景下Apollo的可用性:
場景 | 影響 | 降級 | 原因 |
---|---|---|---|
某臺config service下線 | 無影響 | Config service無狀態(tài)吸占,客戶端重連其它c(diǎn)onfig service | |
所有config service下線 | 客戶端無法讀取最新配置,Portal無影響 | 客戶端重啟時(shí),可以讀取本地緩存配置文件凿宾,如果是新擴(kuò)容的機(jī)器矾屯,可以從其它機(jī)器上獲取已緩存的配置文件。 | |
某臺admin service下線 | 無影響 | Admin service無狀態(tài)初厚,Portal重連其它admin service | |
所有admin service下線 | 客戶端無影響件蚕,portal無法更新配置 | ||
某臺portal下線 | 無影響 | Portal域名通過slb綁定多臺服務(wù)器,重試后指向可用的服務(wù)器 | |
全部portal下線 | 客戶端無影響产禾,portal無法更新配置 | ||
某個數(shù)據(jù)中心下線 | 無影響 | 多數(shù)據(jù)中心部署排作,數(shù)據(jù)完全同步,Meta Server/Portal域名通過slb自動切換到其它存活的數(shù)據(jù)中心 | |
數(shù)據(jù)庫宕機(jī) | 客戶端無影響亚情,Portal無法更新配置 | Config Service開啟配置緩存后妄痪,對配置的讀取不受數(shù)據(jù)庫宕機(jī)影響 |
以上內(nèi)容參考自Apollo GitHub,更多詳細(xì)內(nèi)容請參照官方介紹楞件。