一、基礎模型
- 用戶在配置中心對配置進行修改並發布
- 配置中心通知Apollo客戶端有配置更新
- Apollo客戶端從配置中心拉取最新的配置、更新本地配置並通知到應用

二、架構模塊
- Config Service提供配置的讀取、推送等功能,服務對象是Apollo客戶端
- Admin Service提供配置的修改、發布等功能,服務對象是Apollo Portal(管理界面)
- Config Service和Admin Service都是多實例、無狀態部署,所以需要將自己注冊到Eureka中並保持心跳
- 在Eureka之上我們架了一層Meta Server用於封裝Eureka的服務發現接口
- Client:Apollo提供的客戶端程序,為應用提供配置獲取、實時更新等功能,通過域名訪問Meta Server獲取Config Service服務列表(IP+Port),而后直接通過IP+Port訪問服務,同時在Client側會做load balance、錯誤重試
- Portal提供Web界面供用戶管理配置,通過域名訪問Meta Server獲取Admin Service服務列表(IP+Port),而后直接通過IP+Port訪問服務,同時在Portal側會做load balance、錯誤重試
- 為了簡化部署,我們實際上會把Config Service、Eureka和Meta Server三個邏輯角色部署在同一個JVM進程中

三、選擇Eureka的原因
- 提供了完整的Service Registry和Service Discovery實現
- 和Spring Cloud無縫集成
1)項目本身就使用了Spring Cloud和Spring Boot,同時Spring Cloud還有一套非常完善的開源代碼來整合Eureka,所以使用起來非常方便
2)Eureka還支持在我們應用自身的容器中啟動,也就是說我們的應用啟動完之后,既充當了Eureka的角色,同時也是服務的提供者。這樣就極大的提高了服務的可用性
3)為了提高配置中心的可用性和降低部署復雜度,我們需要盡可能地減少外部依賴 - 開源,由於代碼是開源的,所以非常便於我們了解它的實現原理和排查問題。
四、配置發布后的實時推送設計
- 用戶在Portal操作配置發布
- Portal調用Admin Service的接口操作發布
- Admin Service發布配置后,發送ReleaseMessage給各個Config Service
- Config Service收到ReleaseMessage后,通知對應的客戶端

五、發送ReleaseMesssage的實現方式
- Admin Service在配置發布后,需要通知所有的Config Service有配置發布,從而Config Service可以通知對應的客戶端來拉取最新的配置
- Admin Service在配置發布后會往ReleaseMessage表插入一條消息記錄,消息內容就是配置發布的AppId+Cluster+Namespace
- Config Service有一個線程會每秒掃描一次ReleaseMessage表,看看是否有新的消息記錄
- Config Service如果發現有新的消息記錄,那么就會通知到所有的消息監聽器
- NotificationControllerV2得到配置發布的AppId+Cluster+Namespace后,會通知對應的客戶端

六、ConfigService通知客戶端的實現方式
- 客戶端會發起一個Http請求到Config Service的
notifications/v2接口,也就是NotificationControllerV2 - NotificationControllerV2不會立即返回結果,而是通過Spring DeferredResult把請求掛起
- 如果在60秒內沒有該客戶端關心的配置發布,那么會返回Http狀態碼304給客戶端
- 如果有該客戶端關心的配置發布,NotificationControllerV2會調用DeferredResult的setResult方法,傳入有配置變化的namespace信息,同時該請求會立即返回。客戶端從返回的結果中獲取到配置變化的namespace后,會立即請求Config Service獲取該namespace的最新配置
七、客戶端設計
- 客戶端和服務端保持了一個長連接,從而能第一時間獲得配置更新的推送。(通過Http Long Polling實現)
- 客戶端還會定時從Apollo配置中心服務端拉取應用的最新配置
1)這是一個fallback機制,為了防止推送機制失效導致配置不更新
2)客戶端定時拉取會上報本地版本,所以一般情況下,對於定時拉取的操作,服務端都會返回304 - Not Modified
3)定時頻率默認為每5分鍾拉取一次,客戶端也可以通過在運行時指定System Property:apollo.refreshInterval來覆蓋,單位為分鍾 - 客戶端從Apollo配置中心服務端獲取到應用的最新配置后,會保存在內存中
- 客戶端會把從服務端獲取到的配置在本地文件系統緩存一份(在遇到服務不可用,或網絡不通的時候,依然能從本地恢復配置)
- 應用程序可以從Apollo客戶端獲取最新的配置、訂閱配置更新通知

