Apollo源碼解析看一文就夠


對於配置中心我們先拋出問號三連,什么是配置中心?為什么要用配置中心?配置中心怎么用?

筆者說說自己理解的配置中心,個人觀點的十六字

消息存儲  消息推送  環境隔離  灰度發布

今天我們先來看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,只是圖這里沒有表示出來。

 

我們這里只聊聊實現原理,具體的操作可以參考官方灰度發布指南。如果有任何問題可以留言一起討論。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM