Categories
程式開發

Apollo在有讚的實踐


一. 背景和Apollo簡介

在集中式開發時代,配置文件基本足夠用了,因為那時配置的管理通常不會成為一個很大的問題,簡單一點來說,系統上了生產之後,如果需要修改一個配置,登錄到這台生產機器上,修改這個配置文件,然後reload配置文件並不是什麼很大的負擔。但是在互聯網時代,我們的應用都是分佈式系統,部署在N台機器上,如果在線上一台一台的重啟機器,會造成很大的負擔和不穩定。並且對於公司來說,會有多個環境區分(測試環境和線上環境)​​,有時還需要對同一環境中的不同集群做不同的配置。因此需要一個配置中心來集中管理不同環境、不同集群的配置,修改配置後能夠實時推送到應用端。

Apollo(阿波羅)是攜程框架部門研發的分佈式配置中心,能夠集中化管理應用不同環境、不同集群的配置,配置修改後能夠實時推送到應用端,並且具備規範的權限、流程治理等特性,適用於微服務配置管理場景。 Apollo服務端基於Spring Boot和Spring Cloud開發,打包後可以直接運行,不需要額外安裝Tomcat等應用容器。

二. Apollo在有讚的實踐

2.1 部署方案

多環境支持

在有贊內部,環境的區分為:

  • DAILY:日常環境(供開發自測的環境)
  • QA:測試基準環境
  • PRE:預發環境(上線前的驗證)
  • PROD:線上環境

在Apollo的抽象裡,配置支持環境和集群粒度的隔離。其中環境的隔離是物理的隔離,不同環境是需要單獨的數據庫來支持的,集群則是邏輯隔離,同一環境的不同集群的數據庫是共享的。這就導致一個問題,有贊需要四個環境的隔離,但是底層的RDS只支持三個環境。

如何在這種約束條件下支持四個環境的配置隔離,我們的做法是在PROD環境下創建PRE集群,虛擬為PRE環境,這個方案能夠解決問題,但是會帶來大量的兼容性成本。這裡的兼容性成本包括:

  1. client識別環境和機房的邏輯需要兼容
  2. 控制台的UI需要做調整
  3. 開放平台的sdk需要寫兼容邏輯

而且,因為這種方案本質上破壞了環境和集群的抽象,原有的關於環境的特性以及集群的特性也喪失了,比如虛擬出來的PRE環境不能創建集群,PRE環境的應用會因為集群的降級特性讀取線上環境的配置。

總結來說,多環境的支持是Apollo在有讚的實踐做的最不好的地方,之所以會這樣,根本原因在於對Apollo的抽像沒有理解清晰,所以出現了破壞抽象的定制。

跟ops系統深度集成除了動態配置,Apollo作為配置中心的另一個重要的特性是,配置的中心化管理,將業務配置跟非業務配置隔離開來。這樣隔離的好處在於,業務開發不需要關心框架和中間件的配置了,框架和中間件也能夠更容易的管理各自的配置。 Apollo可以解決其他中間件的配置管理問題,那Apollo自身的配置管理要怎麼解決呢?我們的解決方案是通過ops系統來管理。

下面是Apollo相關的配置,通過運維繫統寫到每個機器上,通過讀取這個文件,可以識別到當前所在的環境、機房以及其他的信息。 Apollo-client就是通過讀取下面的信息來識別相關信息的。

  • APPLICATION-STANDARD-ENV=qa
  • APPLICATION-SERVICE-CHAIN=qa
  • APPLICATION_NAME=carmen-console-ng
  • APPLICATION_IDC=qabb
  • APOLLO_METASERVER=apollo-metaserver-qa.s.qima-inc.co

方案的好處在於,能夠減少業務方錯誤配置帶來的答疑量。

雙機房支持為了帶來最高的穩定性,有贊線上核心應用都是雙機房部署,雙機房部署能夠避免單點問題,增強穩定性。 Apollo作為核心的組建,也需要支持雙機房部署。

雙機房部署要解決的主要問題是,數據如何在兩個機房間同步,因為Apollo底層使用mysql存儲配置數據,所以這個問題就變為不同機房的mysql數據庫如何進行數據的同步,以及某個節點不可用的情況下如何切換。

這裡有必要對有讚的RDS系統做一個介紹,RDS能夠自動實現mysql的主從切換,應用通過RDS proxy來跟server交互,默認情況下,RDS proxy會將寫流量路由到master,讀流量按照配置進行路由。在master節點故障的時候,RDS可以自動實現主從切換,並將寫流量路由到新的master節點。

雙機房部署圖如下

Apollo在有讚的實踐 1

2.2 上雲

有贊不僅僅作為一家SAAS公司,也涉及雲的業務,具體說來,就是有贊會將核心業務沉澱為中台,中台暴露擴展點,外部開發者可以使用這些擴展點來定制自己的SAAS軟件。外部開發者的應用通常託管在有讚的SAAS雲上,這類雲上的應用也有動態配置的需要,Apollo上雲正是為了滿足這個需求。

為了滿足上雲的需要,Apollo需要解決安全性問題,開源的版本缺乏對安全性方面的管控,具體體現在:

  1. 任何應用都可以通過偽造應用名的方式來訪問其他應用的配置
  2. 任何應用都可以訪問公共的配置,而某些公共的配置只能被特定的幾個應用訪問

‍我們給出的解決方案是,給應用頒發憑證,Apollo server會校驗憑證以驗證應用的身份。同時擴展Namespace的模型,增加scope屬性,用來限制該Namespace可被訪問的應用列表,比如Namespace的scope為 [“A”,“B”],表明這個Namespace可以被A應用和B應用訪問。

Apollo在有讚的實踐 2

除了安全性問題,Apollo上雲還需要解決另外一個問題,如何在一個環境中部署多個Apollo環境?因為雲上的Apollo面向的是開發者,開發者使用的是有贊線上的環境,然而對於開發者應用,也是需要區分測試環境和線上環境的。這就帶來一個需求,就是Apollo需要在線上環境支持開發者的測試環境和線上環境的配置隔離。下面展示了線上環境,Apollo的部署情況:

Apollo在有讚的實踐 3

如上圖所示,portal部署在aembd機房,configservice和adminservice在線上環境部署兩個服務(由於公司發布系統的限制,一個應用在一個環境只能部署一個服務,所以要實現這種部署的話,是需要給adminservice和configservice分別申請兩個應用的),分別作為開發者的DEV環境和PROD環境。 baymax是面向開發者的控制台,portal並不直接面向開發者。這種實現方案帶來了很大的運維成本,體現在需要額外申請多個應用和數據庫,後續數據庫DDL變更的成本更高。

其實Apollo的設計裡面,是支持環境和集群兩個緯度的配置隔離的,所以針對這種需求場景,是可以使用集群隔離的特性的。兩個緯度的配置隔離的特性也體現出Apollo設計人員的前瞻性,這裡僅僅是其中一個例子,另外一個例子是資源配置的託管,這個放在後續再做介紹。

2.3 中間件​​配置託管

Apollo的核心抽象Namespace,能夠解決多個應用共享配置的需求,能夠為這類多個應用共享的配置提供統一管理的入口。在有贊內部,各個中間件和框架的配置,都是由Apollo來集中管理的,比如dubbo、分佈式鎖、調用鍊等等。集中託管能夠帶來很多的好處,比如減少業務方的配置成本以及因為配置錯誤引起的答疑量, 便於後續對配置的變更。

這裡可以舉一個例子,大家知道現在service-mesh的概念很火,service-mesh能夠很好的解決多語言調用的問題,而有贊內部除了java以外,node也是一個主要的開發語言。所以公司開發了一套service-mesh組件,並且急需要將java語言的rpc框架替換成service-mesh的解決方案。這種例子中,rpc框架遷移到service-mesh只需要修改rpc框架的某些配置項,因為rpc框架的配置是集中管理的,所以修改很容易。值得一提的是,Apollo對於這種修改場景,為了保證穩定性,還提供了強大的灰度特性。

2.4 資源配置託管

資源的概念可以理解為應用運行時依賴的基礎組件,比如數據庫、消息中間件、緩存系統等等。一個完整的運維流程包括,資源的申請、資源的配置、資源的監控、資源的回收等等。

在使用Apollo託管資源配置之前,有讚的資源配置是託管在另外一個靜態配置系統的,還有另外相當大的一部分是脫離管控的,散落在應用代碼中。在公司的靜態配置系統中,應用對資源配置的引用是通過複製的方式,而非引用的方式,對於資源的管理者,看不到使用該資源配置的應用,對資源配置的變更也需要推動業務方去修改應用的拷貝,對於散落在應用代碼中的配置,要推動改造就更加不可能了。

除了配置管理方面的問題,針對數據庫的配置,有對用戶隱藏的需求,直接把用戶名、密碼暴露出去,容易帶來不可控的風險。解決這個問題的方法是使用統一資源名,業務方只需要感知統一資源名,配置中心將統一資源名跟具體的資源配置映射。

項目的整體架構圖如下,在這個項目中,Apollo配置中心只是整個資源運維流程的一步,承擔了資源配置的統一管理、配置脫敏、變更通知等重要功能。

Apollo在有讚的實踐 4

2.5 接入OPS系統提升產品體驗

有贊有一套自己的ops系統,所有應用的管理、發布,中間件的申請,數據庫權限申請等都在這個平台。所以如果把Apollo控制台的功能遷移統一維護的ops系統,可以大大的增加維護和管理,提升用戶體驗,並且有助於後續的繼續迭代。但是如果需要挨個對接之前Apollo的接口,需要很多的工作量,而且傳遞的參數也有可能因為不一致導致拋錯。除此之外,對於有贊線上不同機房的部署,希望能在ops統一展示不同機房的名稱,而Apollo默認就是default集群。

為了解決這個問題,我們在Apollo之前加了一層代理(Apollo-ops),ops系統所有的請求都會發到Apollo-ops,再由Apollo-ops統一轉換成Apollo的http請求報文格式,獲取請求結果。對於特殊的請求和新增操作Apollo的接口,可以Apollo-ops添加接口,這樣可以減少對Apollo源碼的侵入。 ops控制台界面如圖所示:

Apollo在有讚的實踐 5

三. Apollo架構與設計

3.1 Apollo架構圖

Apollo在有讚的實踐 6

上圖簡要描述了 Apollo 的總體設計,從下往上看:

  • Config Service 提供配置的讀取、推送等功能,服務對像是Apollo客戶端
  • Admin Service 提供配置的修改、發布等功能,服務對像是Apollo Portal(管理界面)
  • 通過Apollo的發布界面可以多環境、集群管理配置
  • Config Service 和 Admin Service 都是多實例、無狀態部署,所以需要將自己註冊到
  • Eureka 中並保持心跳,在 Eureka 之上架了一層 Meta Server 用於封裝 Eureka 的服務發現接口。 Apollo提供了MetaServiceProvider SPI,用戶可以注入自己的MetaServiceProvider來自定義Meta Server定位邏輯
  • Client 通過域名訪問Meta Server獲取Config Service服務列表(IP+Port),而後直接通過IP+Port 訪問服務,同時在 Client 側會做 load balance、錯誤重試

為了簡化部署,我們實際上會把Config Service、Eureka和Meta Server三個邏輯角色部署在同一個JVM進程中。

3.2 Apollo核心設計

3.2.1 Namespace設計

Namespace是配置項的集合,類似於一個配置文件的概念。 Namespace的獲取權限分為兩種:private(私有的)和public(公共的)。 private權限的Namespace,只能被所屬的應用獲取到。一個應用嘗試獲取其它應用private的Namespace,Apollo會報“404”異常。 public權限的Namespace,能被任何應用獲取到。

Namespace類型有三種:

  1. 私有類型
  2. 公共類型
  3. 關聯類型

私有的Namespace具有private權限,默認的“application”的Namespace就是私有類型的。

公共類型的Namespace具有public權限。公共類型的Namespace相當於游離於應用之外的配置,且通過Namespace的名稱去標誌公共Namespace,所以公共的Namespace的名稱必須全局唯一。

如果在不同部分需要共享配置獲取中間件客戶端需要共享時,可以使用公共類型的Namespace。關聯類型又可以稱為繼承類型,關聯類型具有private權限。關聯類型的Namespace繼承於公共類型的Namespace,用於覆蓋公共的Namespace的某些配置項。

3.2.2 Client端實現

Client通過輪詢的方式,從Config Service讀取配置。 Client的輪詢包含兩部分:

  1. RemoteConfigRepository,定時輪詢Config Service的配置讀取 /configs/{appId}/{clusterName}/{namespace:.+}接口。
  2. RemoteConfigLongPollService,長輪詢Config Service的配置變更通知/notifications/v2接口。當有新的通知時,觸發RemoteConfigRepository,立即輪詢Config Service的配置讀取/configs/{appId}/{clusterName}/{namespace:.+}接口。整體流程如圖所示:

Apollo在有讚的實踐 7

3.2.3 Apollo開放平台

Apollo提供了一套的Http REST接口,使第三方應用能夠管理配置。雖然Apollo系統本身提供了Portal來管理配置,但是在一些特殊的場景下,需要程序自己去管理。第三方應用負責人需要提供一些第三方應用基本信息來生成一個Token。

Apollo在有讚的實踐 8

Token獲取成功後,可以給Token綁定可以操作的特定Namespace,或者直接賦予整個應用下所有Namespace的權限。

Apollo在有讚的實踐 9

3.3 Apollo控制台

在有贊,Apollo分為4個環境,分別是daily、qa、pre、prod,在不同環境下可以分別創建不同的集群,在不同集群下可以創建3中類型的Namespace(私有、公共、關聯) 。

Namespace名稱全局唯一,創建需要項目管理員的權限,創建頁面如下:

Apollo在有讚的實踐 10

成功創建Namespace後,可以點擊新增配置來創建配置項,創建完後,提交配置項:

Apollo在有讚的實踐 11

配置只要在發布後才會真的被應用使用到,所以在編輯完配置後,需要發布配置。

Apollo在有讚的實踐 12

四. 未來展望

Apollo已經是一套很成熟的開源配置管理中心軟件,但是由於技術的更新,在一些技術細節上能有更好的優化。

  1. webSocket替代http長輪詢:Apollo在獲取配置信息時,會發起一個長輪詢,即客戶端發送一個超時時間很長的Request,服務器hold住這個連接(Apollo默認是30s),在有新數據達到時返回Response。 http1.1的連接默認使用長連接,雖然長連接在一個TCP連接上可以傳輸多個Request/Response消息對,但是本質上還是會造成資源的浪費、實時性不強等問題。而webSocket只需要建立一次Request/Response消息對,之後都是TCP連接,避免了需要多次建立Request/Response消息對而產生的冗餘頭部信息。當Apollo配置被修改後,服務端可以通知客戶端,客戶端再來獲取最新配置,整個流程可以在一個webSocket中進行。
  2. 配置中心統一:將公司的靜態配置中心和動態配置中心融合起來,使用apollo替換scm的配置中心,這樣做有兩個好處,一是apollo相對於公司的靜態配置中心,提供了更強大的配置集中管理功能,可以提升基礎組件的配置管理能力。另一個原因是減少業務方的使用成本和開發的維護成本。
  3. 用ETCD替換Eureka註冊中心:這個規劃主要考慮到兩點原因,一是將註冊中心的功能從configservice中解耦出來,解耦出來之後configservice就可以切換到容器中,運維成本降低。另一個原因是因為ETCD是公司核心的註冊中心組件,穩定性更高。

本文轉載自公眾號有贊coder(ID:youzan_coder)。

原文鏈接

https://mp.weixin.qq.com/s?__biz=MzAxOTY5MDMxNA==&mid=2455760533&idx=1&sn=c30da495cd09e23cab7d43602d36c823&chksm=8c6868b0bb1fe1a66eeaf12e525b78aaded632c31c5d9dc1b09ea61b63256c3dce82400be88e&scene=27#wechat_redirect