前言
公司裡面使用的配置中心是攜程開源的Apollo
,之前我只使用過Nacos
,遂記錄一下學習過程。
Apollo工作原理
模組介紹
上圖就是Apollo的總體設計,從下往上挨個分析:
- ConfigDB用於儲存各種配置
- Config Service提供配置的讀取、推送等功能,服務物件是Apollo客戶端,多例項,需要註冊到Eureka中保持心跳檢測
- Admin Service提供配置的修改、釋出等功能,服務物件是Apollo Portal(管理介面),多例項,需要註冊到Eureka中保持心跳檢測
- Eureka提供服務註冊和發現,為了簡單起見,目前Eureka在部署時和Config Service是在一個JVM程序中
- Meta Server用於封裝Eureka的服務發現介面
- Client透過域名訪問Meta Server獲取Confifig Service服務列表(IP+Port),而後直接透過IP+Port訪問服務,同時在Client側會做load balance、錯誤重試
- Portal透過域名訪問Meta Server獲取Admin Service服務列表(IP+Port),而後直接透過IP+Port訪問服務,同時在Portal側會做load balance、錯誤重試
執行流程
- Apollo啟動後,Config/Admin Service會自動註冊到Eureka服務註冊中心,並定期傳送保活心跳;
- Apollo Client和Portal管理端透過配置的Meta Server的域名地址經由Software Load Balancer(軟體負載均衡器)進行負載均衡後分配到某一個Meta Server;
- Meta Server從Eureka獲取Config Service和Admin Service的服務資訊,相當於是一個Eureka Client;
- Meta Server獲取Config Service和Admin Service(IP+Port)失敗後會進行重試;
- 獲取到正確的Config Service和Admin Service的服務資訊後,Apollo Client透過Config Service為應用提供配置獲取、實時更新等功能;Apollo Portal管理端透過Admin Service提供配置新增、修改、釋出等功能。
基本概念
- application (應用)
實際使用配置的應用,Apollo客戶端在執行時需要知道當前應用是誰,從而可以去獲取對應的配置。關鍵字:appId - environment (環境)
配置對應的環境,Apollo客戶端在執行時需要知道當前應用處於哪個環境,從而可以去獲取應用的配置。關鍵字:env - cluster (叢集)
一個應用下不同例項的分組,比如典型的可以按照資料中心分,把上海機房的應用例項分為一個叢集,把北京機房的應用例項分為另一個叢集。關鍵字:cluster - namespace (名稱空間)
一個應用下不同配置的分組,可以簡單地把namespace類比為檔案,不同型別的配置存放在不同的檔案中,如資料庫配置檔案,RPC配置檔案,應用自身的配置檔案等。關鍵字:namespaces
關係圖如下所示:
專案管理
部門管理
apollo 預設部門有兩個。要增加自己的部門,可在系統引數中修改,進入系統引數,輸入key查詢已存在的部門設定:organizations
修改value值來新增新部門,下面新增一個微服務部門:
[{"orgId":"TEST1","orgName":"樣例部門1"},{"orgId":"TEST2","orgName":"樣例部門2"},{"orgId":"micro_service","orgName":"微服務部門"}]
建立專案
- 開啟apollo主頁,點選建立應用:
- 輸入相關資訊,包括部門、應用AppId、應用名稱和應用負責人
- 將專案授予使用者管理服務的許可權,點選授權
- 使用zhangsan賬號登陸,就可以看到能管理的應用了
刪除專案
如果要刪除整個專案,點選右上角的管理員工具,再點選刪除應用、叢集。
首先查出壓迫刪除的專案是,然後點選刪除應用:
配置管理
釋出配置
- 透過表格模式新增:
- 透過文字模式批次新增:
- 最後點選右上角釋出按鈕釋出配置。
修改配置
找到需要修改的配置項,進行修改
修改完進行提交,之後在重新發布配置。
刪除配置
與上面一樣,刪除配置後重新發布。
設定私有Namespace
Namespace同樣也可以當作一個配置檔案,以rocketmq配置為例,新增“spring-rocketmq” Namespace配置rocketmq相關資訊。
- 建立名稱空間
- 新增配置項
- 進行釋出。
設定公共Namespace
在專案開發中,有一些配置可能是通用的,我們可以透過把這些通用的配置放到公共的Namespace中,這樣其他專案要使用時可以直接新增需要的Namespace。
新增配置
- 新建一個common-template專案
- 新增公共Namespace:spring-boot-http
- 新增配置項併發布
關聯公共Namespcae
建立完公共名稱空間之後,需要將專案進行關聯才能使用。
開啟之前建立的account-service專案,點選左側的新增Namespace,再新增Namespace:
若是當前專案需要的配置與公共配置中提供的不一樣,也可以根據需求覆蓋定製配置。
讀取配置
讀取某個叢集的配置,需要啟動應用時在VM option
指定具體的應用、環境和叢集。
-Dapp.id=應用名稱
-Denv=環境名稱
-Dapollo.cluster=叢集名稱
-D環境_meta=meta地址
具體例項如下:
‐Dapp.id=account‐service
‐Denv=DEV
‐Dapollo.cluster=SHAJQ
‐Dapollo.meta=http://localhost:8080
配置釋出原理分析
在配置中心中,一個重要的功能就是配置釋出後實時推送到客戶端。下面我們簡要看一下這塊是怎麼設計實現的:
- 使用者在Portal操作配置釋出
- Portal呼叫Admin Service的介面操作釋出
- Admin Service釋出配置後,傳送ReleaseMessage給各個Config Service
- Config Service收到ReleaseMessage後,通知對應的客戶端
原始碼分析
傳送ReleaseMessage
Admin Service在配置釋出後,需要通知所有的Config Service有配置釋出,從而Config Service可以通知對應的客戶端來拉取最新的配置。
從概念上來看,這是一個典型的訊息使用場景,Admin Service作為producer(生產者)發出訊息,各個Config Service作為consumer(消費者)消費訊息。透過一個訊息佇列元件(Message Queue)就能很好的實現Admin Service和Config Service的解耦。
在實現上,考慮到Apollo的實際使用場景,以及為了儘可能減少外部依賴,Apollo沒有采用外部的訊息中介軟體,而是透過資料庫實現了一個簡單的訊息佇列。
具體實現如下:
-
Admin Service在配置釋出後會往ReleaseMessage表插入一條訊息記錄,訊息內容就是配置釋出的AppId+Cluster+Namespace:
訊息傳送類:DatabaseMessageSende
-
Config Service有一個執行緒會每秒掃描一次ReleaseMessage表,看看是否有新的訊息記錄。
訊息掃描類:ReleaseMessageScanner
-
Config Service如果發現有新的訊息記錄,那麼就會通知到所有的訊息監聽器
-
有一個類叫NotifificationControllerV2,當它得到配置釋出的AppId+Cluster+Namespace後,會通知對應的客戶端。
- 客戶端會發起一個Http請求到Config Service的 notifications/v2 介面NotificationControllerV2
- NotificationControllerV2不會立即返回結果,而是把請求掛起。考慮到會有數萬客戶端向服務端發起長連,因此在服務端使用了async servlet(Spring DeferredResult)來服務Http Long Polling請求。
- 如果在60秒內沒有該客戶端關心的配置釋出,那麼會返回Http狀態碼304給客戶端。
- 如果有該客戶端關心的配置釋出,NotificationControllerV2會呼叫DeferredResult的setResult方法,傳入有配置變化的namespace資訊,同時該請求會立即返回。客戶端從返回的結果中獲取到配置變化的namespace 後,會立即請求Config Service獲取該namespace的最新配置。
- 除此之外,客戶端還會定時從Apollo配置中心服務端拉取應用的最新配置,防止推送機制失效導致配置不更新,提升了可用性,預設定時拉取頻率是5分鐘。
- 客戶端會發起一個Http請求到Config Service的 notifications/v2 介面NotificationControllerV2