對於配置中心我們先拋出問號三連,什麼是配置中心?為什麼要用配置中心?配置中心怎麼用? 筆者說說自己理解的配置中心,個人觀點的十六字 消息存儲 消息推送 環境隔離 灰度發佈 今天我們先來看Apollo配置中心怎麼用,小伙伴可能會說,這不是很簡單嘛,no,我們同時要來揭開配置保存的實現原理。 apoll ...
對於配置中心我們先拋出問號三連,什麼是配置中心?為什麼要用配置中心?配置中心怎麼用?
筆者說說自己理解的配置中心,個人觀點的十六字
消息存儲 消息推送 環境隔離 灰度發佈
今天我們先來看Apollo配置中心怎麼用,小伙伴可能會說,這不是很簡單嘛,no,我們同時要來揭開配置保存的實現原理。
apollo配置都是通過表來保存,那麼我們來一步一步揭開模型關係。
看筆者這篇文章的同時,或者你已經熟悉Apollo基本的操作,比如創建集群、創建Namespace、創建灰度發佈等。如果不熟悉,可以參考小編上篇文章自己構建Apollo調試環境,參考官方 Apollo使用指南。
創建項目
為了小伙伴能看的清楚,筆者特意把表數據全部清理了,包括原始項目,項目id是100004458
那麼我們先創建一個項目,這個項目可以匹配我們自己的服務,比如platform-base-service
這裡解答兩個問題,應用負責人是在管理員工具-用戶管理中配置,對應表是ApolloPortalDB.Users
部門是可選項,配置的是ApolloPortalDB.ServerConfig中 organizations對應value,可以看到筆者這裡配置的造火箭的部門和擰螺絲的部門
當然可以在系統工具--管理員參數 配置key=organizations和value=[{"orgId":"TEST1","orgName":"造火箭部門"},{"orgId":"TEST2","orgName":"擰螺絲部門"}]
這裡我們也可以擴展一點,
到此我們項目已經創建完成。
環境列表
這個看過筆者寫的Apollo源碼搭建調試看一文就夠,應該知道,筆者特意強調了只配置dev環境,也就是ApolloPortalDB.ServerConfig中Key=apollo.portal.envs和Value=dev
這裡再強調一次ApolloPortalDB所有環境只需要部署一個即可,而ApolloConfigDB需要在每個環境部署一套,如dev、fat、uat和pro分別部署4套ApolloConfigDB。
每個環境下ApolloConfigDB 配置獨立。這裡也是我們說到的配置中心需要實現的環境隔離。
如果需要配置多環境,按照工程源碼下../apollo/scripts/apollo-on-kubernetes/db下對應環境創建自己的ApolloConfigDB數據度,然後配置apollo.portal.envs,當然也可以自定義環境。
添加集群 Cluster
集群使用場景,類似異地多活,同一個項目不用城市獲取的配置項是不同的。
- 通過添加集群,可以使同一份程式在不同的集群(如不同的數據中心)使用不同的配置
- 如果不同集群使用一樣的配置,則沒有必要創建集群
表結構比較簡單,ApolloConfigDB.Cluster表中
添加NameSpaces
Apollo在創建項目的時候,都會預設創建一個“application”的Namespace。
對於概念不夠理解,可以看看官方提供的解釋 Apollo核心概念之“Namespace”。
我們來看看表數據流向,創建App也是同種方式,數據都是從portal Service到Admin Service。
下麵我們簡單看下ApolloConfigDB中數據模型關係。
總結如下:
1、創建App後,會自動創建預設的Namespace,預設的Cluster,即同時App、Cluster、AppNamespace、Namespace數據。
2、創建Cluster後,Namespace就是關聯AppNamespace和Cluster,即為每個 AppNamespace 創建 不同集群的Namespace。
借用官方作者的話,如果把appnamespace比作class的話,namespace就可以比作是實例化的對象,它在不同的環境,不同的集群都有實例。
這裡筆者也有一個疑惑,創建namespace會創建所有環境、所有集群,具體後面可以跟蹤下 https://github.com/ctripcorp/apollo/issues/2188
新增配置
這個Item ,配置項,是 Namespace 下最小顆粒度的單位。在 Namespace 分成五種類型:properties yml yaml json xml
數據存儲在ApolloConfigDB.Item
發佈配置
這裡也是我們說到的配置中心需要實現的消息推送。
這裡也就是全文的重點
服務端實時推送如何設計
重點來看看 ReleaseMessage實現方式 1、Admin Service在配置發佈後會往ReleaseMessage表插入一條消息記錄,消息內容就是配置發佈的AppId+Cluster+Namespace,參見DatabaseMessageSender 2、Apollo.ReleaseMessageScanner線程會每秒掃描一次ReleaseMessage表,看看是否有新的消息記錄,參見ReleaseMessageScanner 3、Config Service如果發現有新的消息記錄,那麼就會通知到所有的消息監聽器(ReleaseMessageListener),如NotificationControllerV2,消息監聽器的註冊過程參見ConfigServiceAutoConfiguration 4、NotificationControllerV2得到配置發佈的AppId+Cluster+Namespace後,會通知對應的客戶端
Config Service 通知客戶端的實現方式
上面有提到其實就是NotificationControllerV2在得知有配置發佈後通知客戶端,實現如下 1、客戶端會發起一個Http請求到Config Service的notifications/v2介面,也就是NotificationControllerV2,參見RemoteConfigLongPollService 2、NotificationControllerV2不會立即返回結果,而是通過Spring DeferredResult把請求掛起 3、如果在60秒內沒有該客戶端關心的配置發佈,那麼會返回Http狀態碼304給客戶端 4、如果有該客戶端關心的配置發佈,NotificationControllerV2會調用DeferredResult的setResult方法,傳入有配置變化的namespace信息,同時該請求會立即返回。客戶端從返回的結果中獲取到配置變化的namespace後,會立即請求Config Service獲取該namespace的最新配置。
拋出幾個問題:
1、客戶端收到通知消息後,從返回的結果中獲取到配置變化的 namespace 後,會立即請求 Config Service 獲取該 namespace 的最新配置,問題就是為什麼不在通知消息中帶過去message,而需要重新獲取?
2、假設一個公共 Namespace 有10W台機器使用,該公共 Namespace 發佈時直接下發配置更新消息的話,就會導致這 10W 台機器同時來請求配置,對Config Service的壓力也會特別大如何處理?
實例列表
實例( Instance ),實際就是 Apollo 的客戶端
我們啟動服務 SpringBootSampleApplication,即啟動了一個Apollo客戶端,可以查詢到實例列表。
對應我們的資料庫即ApolloConfigDB.Instance
灰度發佈
這裡也是我們說到的配置中心需要實現的灰度發佈。
我們可以理解灰度和分支等價,
- 創建 Namespace 灰度時:
- 會創建子 Cluster ,指向父 Cluster 。
- 會創建子 Namespace ,關聯子 Namespace 。實際上,子 Namespace 和 父 Namespace 無任何數據欄位上的關聯。
- 向子 Namespace 添加 Item 時,該 Item 指向子 Namespace 。雖然,代碼實現和父 Namespace 是一模一樣的。
灰度發佈模型
灰度 Namespace 發佈 Release 。灰度 Namespace 會自動繼承 父 Namespace 已經發佈的配置。若有相同的配置項,使用 子 Namespace 的。配置處理的邏輯上,和關聯 Namespace 是一致的。
灰度全量發佈
資料庫對應模型
前面我們已經講了每個流程操作的資料庫和關係,這裡我們總結下。
創建項目、集群、namespace數據關係模型
添加配置項數據關係
發佈配置數據關係
上面操作都設計到日誌審計表ApolloConfigDB.Audit,只是圖這裡沒有表示出來。
我們這裡只聊聊實現原理,具體的操作可以參考官方灰度發佈指南。如果有任何問題可以留言一起討論。