通過學習 Apollo 的架構,帶你深入理解微服務架構的基本原理
一、介紹
Apollo(阿波羅)[參考附錄] 是攜程框架部研發並開源的一款生產級的配置中心產品,它能夠集中管理應用在不同環境、不同集群的配置,配置修改后能夠實時推送到應用端,並且具備規范的權限、流程治理等特性,適用於微服務配置管理場景。
Apollo 目前在國內開發者社區比較熱,在 Github 上有超過 5k 顆星,在國內眾多互聯網公司有落地案例,可以說 Apollo 是目前配置中心產品領域 Number1 的產品,其成熟度和企業級特性要遠遠強於 Spring Cloud 體系中的 Spring Cloud Config 產品。
Apollo 采用分布式微服務架構,它的架構有一點復雜,Apollo 的作者宋順雖然給出了一個架構圖,但是如果沒有一定的分布式微服務架構基礎的話,則普通的開發人員甚至是架構師也很難一下子理解。為了讓大家更好的理解 Apollo 的架構設計,我花了一點時間把 Apollo 的架構按我的方式重新剖析一把。只有完全理解了 Apollo 的架構,大家才能在生產實踐中更好的部署和使用 Apollo。另外,通過學習 Apollo 的架構,大家可以深入理解微服務架構的一些基本原理。
二、架構和模塊
下圖是 Apollo 的作者宋順給出的架構圖:
如果沒有足夠的分布式微服務架構的基礎,對攜程的一些框架產品 (比如 Software Load Balancer(SLB) 不了解的話,那么這個架構圖第一眼看是不太好理解的 (其實我第一次看到這個架構也沒有看明白)。在這里我們先放一下,等我后面把這個架構再重新剖析一把以后,大家再回過頭來看這個架構就容易理解了。
下面是 Apollo 的七個模塊,其中四個模塊是和功能相關的核心模塊,另外三個模塊是輔助服務發現的模塊:
四個核心模塊及其主要功能
模塊 | 主要功能 |
---|---|
ConfigService | 提供配置獲取接口 提供配置推送接口 服務於Apollo客戶端 |
AdminService | 提供配置管理接口 提供配置修改發布接口 服務於管理界面Portal |
Client | 為應用獲取配置,支持實時更新 通過MetaServer獲取ConfigService的服務列表 使用客戶端軟負載SLB方式調用ConfigService |
Portal | 配置管理界面 通過MetaServer獲取AdminService的服務列表 使用客戶端軟負載SLB方式調用AdminService |
三個輔助服務發現模塊
模塊 | 主要功能 |
---|---|
Eureka | 用於服務發現和注冊 Config/AdminService注冊實例並定期報心跳 和ConfigService住在一起部署 |
MetaServer | Portal通過域名訪問MetaServer獲取AdminService的地址列表 Client通過域名訪問MetaServer獲取ConfigService的地址列表 相當於一個Eureka Proxy 邏輯角色,和ConfigService住在一起部署 |
NginxLB | 和域名系統配合,協助Portal訪問MetaServer獲取AdminService地址列表 和域名系統配合,協助Client訪問MetaServer獲取ConfigService地址列表 和域名系統配合,協助用戶訪問Portal進行配置管理 |
三、架構剖析
Apollo 架構 V1
如果不考慮分布式微服務架構中的服務發現問題,Apollo 的最簡架構如下圖所示:
要點:
- ConfigService 是一個獨立的微服務,服務於 Client 進行配置獲取。
- Client 和 ConfigService 保持長連接,通過一種拖拉結合 (push & pull) 的模式,實現配置實時更新的同時,保證配置更新不丟失。
- AdminService 是一個獨立的微服務,服務於 Portal 進行配置管理。Portal 通過調用 AdminService 進行配置管理和發布。
- ConfigService 和 AdminService 共享 ConfigDB,ConfigDB 中存放項目在某個環境的配置信息。ConfigService/AdminService/ConfigDB 三者在每個環境 (DEV/FAT/UAT/PRO) 中都要部署一份。
- Protal 有一個獨立的 PortalDB,存放用戶權限、項目和配置的元數據信息。Protal 只需部署一份,它可以管理多套環境。
Apollo 架構 V2
為了保證高可用,ConfigService 和 AdminService 都是無狀態以集群方式部署的,這個時候就存在一個服務發現問題:Client 怎么找到 ConfigService?Portal 怎么找到 AdminService?為了解決這個問題,Apollo 在其架構中引入了 Eureka 服務注冊中心組件,實現微服務間的服務注冊和發現,更新后的架構如下圖所示:
要點:
- Config/AdminService 啟動后都會注冊到 Eureka 服務注冊中心,並定期發送保活心跳。
- Eureka 采用集群方式部署,使用分布式一致性協議保證每個實例的狀態最終一致。
Apollo 架構 V3
我們知道 Eureka 是自帶服務發現的 Java 客戶端的,如果 Apollo 只支持 Java 客戶端接入,不支持其它語言客戶端接入的話,那么 Client 和 Portal 只需要引入 Eureka 的 Java 客戶端,就可以實現服務發現功能。發現目標服務后,通過客戶端軟負載 (SLB,例如 Ribbon) 就可以路由到目標服務實例。這是一個經典的微服務架構,基於 Eureka 實現服務注冊發現 + 客戶端 Ribbon 配合實現軟路由,如下圖所示:
Apollo 架構 V4
在攜程,應用場景不僅有 Java,還有很多遺留的.Net 應用。Apollo 的作者也考慮到開源到社區以后,很多客戶應用是非 Java 的。但是 Eureka(包括 Ribbon 軟負載) 原生僅支持 Java 客戶端,如果要為多語言開發 Eureka/Ribbon 客戶端,這個工作量很大也不可控。為此,Apollo 的作者引入了 MetaServer 這個角色,它其實是一個 Eureka 的 Proxy,將 Eureka 的服務發現接口以更簡單明確的 HTTP 接口的形式暴露出來,方便 Client/Protal 通過簡單的 HTTPClient 就可以查詢到 Config/AdminService 的地址列表。獲取到服務實例地址列表之后,再以簡單的客戶端軟負載 (Client SLB) 策略路由定位到目標實例,並發起調用。
現在還有一個問題,MetaServer 本身也是無狀態以集群方式部署的,那么 Client/Protal 該如何發現 MetaServer 呢?一種傳統的做法是借助硬件或者軟件負載均衡器,例如在攜程采用的是擴展后的 NginxLB(也稱 Software Load Balancer),由運維為 MetaServer 集群配置一個域名,指向 NginxLB 集群,NginxLB 再對 MetaServer 進行負載均衡和流量轉發。Client/Portal 通過域名 +NginxLB 間接訪問 MetaServer 集群。
引入 MetaServer 和 NginxLB 之后的架構如下圖所示:
Apollo 架構 V5
V4 版本已經是比較完成的 Apollo 架構全貌,現在還剩下最后一個環節:Portal 也是無狀態以集群方式部署的,用戶如何發現和訪問 Portal?答案也是簡單的傳統做法,用戶通過域名 +NginxLB 間接訪問 Portal 集群。
所以 V5 版本是包括用戶端的最終的 Apollo 架構全貌,如下圖所示:
四、結論
- 經過我在第三部分的剖析之后,相信大家對 Apollo 的微服務架構會有更清晰的認識,作為一個思考題,大家再回頭看一下第二部分宋順給出的架構圖,現在是否能夠理解?它和我的架構是如何對應的?提示一下,宋順的視角是一個從上往下的俯視視角,而我的是一個側面視角。
- ConfgService/AdminService/Client/Portal 是 Apollo 的四個核心微服務模塊,相互協作完成配置中心業務功能,Eureka/MetaServer/NginxLB 是輔助微服務之間進行服務發現的模塊。
- Apollo 采用微服務架構設計,架構和部署都有一些復雜,但是每個服務職責單一,易於擴展。另外,Apollo 只需要一套 Portal 就可以集中管理多套環境 (DEV/FAT/UAT/PRO) 中的配置,這個是它的架構的一大亮點。
- 服務發現是微服務架構的基礎,在 Apollo 的微服務架構中,既采用 Eureka 注冊中心式的服務發現,也采用 NginxLB 集中 Proxy 式的服務發現。