本文分享自華為雲社群《華為雲FunctionGraph構建高可用系統的實踐》,作者: 華為雲PaaS服務小智。
導語
每年,網上都會報導XXX系統異常不可用,給客戶帶來巨大的經濟損失。雲服務的客戶基數更大,一旦出現問題,都將給客戶和服務自身帶來極大影響。本文將基於華為雲FunctionGraph自身的實踐,詳細介紹如何構建高可用的Serverless計算平臺,實現客戶和平臺雙贏。
高可用介紹
高可用性[1](英語:high availability,縮寫為 HA),IT術語,指系統無中斷地執行其功能的能力,代表系統的可用性程度。是進行系統設計時的準則之一。
業界一般使用 SLA指標來衡量系統的可用性。
服務級別協議[2](英語:service-level agreement,縮寫SLA)也稱服務等級協議、服務水平協議,是服務提供商與客戶之間定義的正式承諾。服務提供商與受服務客戶之間具體達成了承諾的服務指標——質量、可用性,責任。例如,服務提供商對外承諾99.99%的SLA,則全年服務失效時間最大為 5.26 分鐘(365*24*60*0.001%)。
FunctionGraph直觀度量系統可用性的兩個黃金指標,SLI和時延,SLI是系統的請求成功率指標,時延是系統處理的效能。
高可用挑戰
FunctionGraph作為華為雲中的子服務,在構建自身能力的同時,不僅要考慮系統本身的健壯性,也要考慮周邊依賴服務的健壯性(例如依賴的身份認證服務不可用了,進行流量轉發的閘道器服務服務當機了,儲存物件的服務訪問失敗了等等)。除此之外,系統依賴的硬體資源故障或者系統突然遭到流量攻擊等,面臨這些不可控的異常場景,系統如何構建自己的能力來保持業務高可用是一個很大的挑戰。圖一展示了FunctionGraph的周邊互動。
圖1 FunctionGraph的周邊互動
針對常見的問題,梳理出了4個大類,如表1所示。
表1 FunctionGraph常見問題總結
針對這些問題,我們總結了如下幾類通用的治理辦法:
- 流量突變治理:過載保護+彈性擴縮容+熔斷+非同步削峰+監控告警,基於防禦式的設計思想,透過過載保護+熔斷確保系統所有資源受控,然後在此基礎上透過提供極致的擴容能力來滿足大流量,合適的客戶場景推薦非同步削峰來減緩系統壓力,監控告警用來及時發現過載問題。
- 系統服務異常治理:容災架構+重試+隔離+監控告警,透過容災架構避免系統整個當機,透過重試來減少系統異常對客戶業務的影響,透過隔離快速剝離系統異常點,防止故障擴散,透過監控告警快速發現系統服務異常問題。
- 系統依賴服務異常治理:容災架構+快取降級+監控告警,透過容災架構減少依賴服務單點故障,透過快取降級確保依賴服務故障後系統仍能正常執行,透過監控告警快速發現依賴服務異常問題。
- 變更引起治理:灰度升級+流程管控+監控告警,透過灰度升級避免正式客戶由於系統升級異常而造成的全域性故障,透過流程管控將人為變更的風險降到最低,透過監控告警快速發現變更後的故障。
FunctionGraph系統設計實踐
為了解決表1出現的問題,FunctionGraph在架構容災、流控、重試、快取、灰度升級、監控告警、管理流程上等多方面做了最佳化,可用性大幅提升。下面主要介紹一些FunctionGraph面向異常的設計實踐,在彈效能力、系統功能等暫不展開。
容災架構
實現華為雲容災1.1架構(例:服務AZ級故障域、叢集跨AZ自愈能力、AZ級服務依賴隔離),FunctionGraph管理面和資料面叢集部署多套,每套叢集AZ隔離,實現同region內的AZ容災。如圖2所示,FunctionGraph部署多套資料面叢集(承擔FunctionGraph函式執行業務)和dispatcher排程叢集(承擔FunctionGraph的流量叢集排程任務),用來提升系容量以及容災。當前其中某個元戎叢集異常時,dispatcher排程元件能及時摘除故障叢集,並將流量分發至其他幾個叢集。
圖2 FunctionGraph簡略架構圖
分散式無中心化架構設計,支援靈活的橫向擴縮容這個策略是邏輯多租服務設計的關鍵,需要解決無中心化後,元件擴縮容後的重均衡問題。
靜態資料管理的無中心化:邏輯多租服務的後設資料,初期由於量少,可以全部儲存到同一套中介軟體中。隨著客戶上量,需要設計資料的拆分方案,支援資料的分片,應對後續海量資料讀寫,以及可靠性壓力。
流量排程功能的無中心化:元件功能設計,支援無中心化(常見中心化依賴:鎖、流控值、排程任務等),流量上量後,可擴充套件元件副本數量,元件透過自均衡策略,完成流量的重新負載。
多維度的流控策略
FunctionGraph上的客戶函式流量最終達到runtime執行時之前,會經過多個鏈路,每個鏈路都有可能出現超過其承載閾值的流量。因此,為了確保各個鏈路的穩定性,FunctionGraph在每條鏈路上,防禦性的追加了不同的流控策略。基本原則解決計算(cpu)、儲存(磁碟、磁碟I/0)、網路(http連線、頻寬)上的函式粒度的資源隔離。
函式流量從客戶側觸發,最終執行起來的鏈路流控如圖3所示。
圖3 FunctionGraph流控
閘道器APIG流控APIG是FunctionGraph的流量入口,支援Region級別總的流量控制,可以根據region的業務繁忙程度進行彈性擴容。同時APIG支援客戶級別的流量控制,當檢測到客戶流量異常時,可以快速透過APIG側限制客戶流量,減少個別客戶對系統穩定性的影響。
系統業務流控
針對api級別的流控客戶流量透過APIG後,走到FunctionGraph的系統側。基於APIG流控失效的場景,FunctionGraph構建了自身的流控策略。當前支援節點級別流控、客戶api總流控、函式級別流控。當客戶流量超過FunctionGraph的承載能力時,系統直接拒絕,並返回429給客戶。
系統資源流控FunctionGraph是邏輯多租服務,控制面和資料面的資源是客戶共享的,當非法客戶惡意攻擊時,會造成系統不穩定。FunctionGraph針對共享資源實現基於請求併發數的客戶流控,嚴格限制客戶可用的資源。另外對共享資源的資源池化來保證共享資源的總量可控制,進而保證系統的可用性。例如:http連線池、記憶體池、協程池。
併發數控制:構建基於請求併發數的FunctionGraph函式粒度的流控策略,FunctionGraph的客戶函式執行時間有毫秒、秒、分鐘、小時等多種型別,常規的QPS每秒請求數的流控策略在處理超長執行的請求時有先天不足,無法限制同一時刻客戶佔用的系統共享資源。基於併發數的控制策略,嚴格限制了同一時刻的請求量,超過併發數直接拒絕,保護系統共享資源。
http連線池:構建高併發的服務時,合理的維護http的長連線數量,能最大限度減少http連線的資源開銷時間,同時保證http連線數資源的可控,確保系統安全性的同時提升系統效能。業界可以參考http2的連線複用,以及fasthttp內部的連線池實現,其原理都是儘量減少http的數量,複用已有的資源。
記憶體池:客戶的請求和響應報文特別大,同時併發特別高的場景下,單位時間佔用系統的記憶體較大,當超過閾值後,會輕鬆造成系統記憶體溢位,導致系統重啟。基於此場景,FunctionGraph新增了記憶體池的統一控制,在請求入口和響應出口,校驗客戶請求報文是否超過閾值,保護系統記憶體可控。
協程池:FunctionGraph構建於雲原生平臺上,採用的go語言。如果每一個請求都使用一個協程來進行日誌和指標的處理,大併發請求來臨時,導致有海量的協程在併發執行,造成系統的整體效能大幅下降。FunctionGraph引入go的協程池,透過將日誌和指標的處理任務改造成一個個的job任務,提交到協程池中,然協程池統一處理,大幅緩解了協程爆炸的問題。
非同步消費速率控制:非同步函式呼叫時,會優先放到FunctionGraph的kafka中,透過合理設定客戶的kafka消費速率,確保函式例項始終夠用,同時防止過量的函式呼叫,導致底層資源被迅速耗光。
函式例項控制
- 客戶例項配額:透過限制客戶總配額,防止惡意客戶將底層資源耗光,來保障系統的穩定性。當客戶業務確實有需要,可以透過申請工單的方式快速擴充客戶配額。
- 函式例項配額:透過限制函式配額,防止單個客戶的函式將客戶的例項耗光,同時也能防止客戶配額失效,短時間內造成大量的資源消耗。另外,客戶業務如果涉及資料庫、redis等中介軟體的使用,透過函式例項配額限制,可以保護客戶的中介軟體連線數在可控範圍內。
流控屬於防禦式設計思想,透過提前封堵的方式減少系統過載的風險。客戶正常業務突發上量需要大量的資源時,首先應該解決的是資源彈性問題,保證客戶業務成功的前提下,透過流控策略兜底系統出現異常,防止爆炸面擴散。FunctionGraph支援叢集節點快速彈性、支援客戶函式例項快速彈性、支援客戶函式例項的智慧預測彈性等多種彈效能力,保證客戶業務突增時依然能正常使用FunctionGraph。
重試策略FunctionGraph透過設計恰當好處的重試策略,使系統在發生異常的時候,也可以保障客戶的請求最終執行成功。如圖4所示,重試的策略一定要有終止條件,否則會造成重試風暴,更輕鬆的擊穿系統的承載上限。
圖4 重試策略
函式請求失敗重試- 同步請求:當客戶請求執行時,遇到系統錯誤時,FunctionGraph會將請求轉發至其他叢集,最多重試3次,確保客戶的請求,在遇到偶現的叢集異常,也可以在其他叢集執行成功。
- 非同步請求:由於非同步函式對實時性要求不高,客戶函式執行失敗後,系統可以針對失敗請求做更為精細的重試策略。當前FunctionGraph支援二進位制指數退避的重試,當函式由於系統錯誤異常終止後,函式會按2,4,8,16指數退避的方法,當間隔退避到20分鐘時,後續重試均按照20分的間隔進行,函式請求重試時間最大支援6小時,當超過後,會按失敗請求處理,返回給客戶。透過二進位制指數退避的方式,可以最大程度保障客戶業務的穩定性。
- 中介軟體的重試機制:以redis為例,當系統讀寫redis偶現失敗時,會sleep一段時間,再重複執行redis的讀寫操作,最大重試次數3次。
- http請求重試機制:當http請求由於網路波動,發生eof、io timeout之類的錯誤時,會sleep一段時間,在重複http的傳送操作,最大重試次數3次。
快取不僅可以加速資料的訪問,而且當依賴的服務故障時,仍然可以使用快取資料,保障系統的可用性。從功能類別劃分,FunctionGraph需要進行快取的元件有兩類,1是中介軟體,2是依賴的雲服務,系統優先訪問快取資料,同時定期從中介軟體和依賴的雲服務重新整理本地快取資料。方式如圖5所示。
- 快取中介軟體資料:FunctionGraph透過釋出訂閱的方式,監聽中介軟體資料的變化及時更新到本地快取,當中介軟體異常時,本地快取可以繼續使用,維持系統的穩定性。
- 快取關鍵依賴服務資料:以華為雲的身份認證服務IAM為例,FunctionGraph會強依賴IAM,當客戶發起首次請求,系統會將token快取到本地,過期時間24小時,當IAM掛掉後,不影響老的請求。FunctionGraph系統的使用。其他關鍵的雲服務依賴做法一直,都是把關鍵的資料臨時快取到本地記憶體。
圖5 FunctionGraph的快取措施
熔斷上面的種種措施,可以保障客戶業務平穩執行,但當客戶業務出現異常一直無法恢復或者有惡意客戶持續攻擊FunctionGraph平臺,系統資源會一直浪費在異常流量上,擠佔正常客戶的資源,同時系統可能會在持續高負荷執行異常流量後出現不可預期的錯誤。針對這種場景,FunctionGraph基於函式呼叫量模型構建了自身的斷路器策略。具體如圖6所示,根據呼叫量的失敗率進行多級熔斷,保證客戶業務的平滑以及系統的穩定。
圖6 熔斷策略模型
隔離
- 非同步函式業務隔離:按照非同步請求的類別,FunctionGraph將Kafka的消費組劃分為定時觸發器消費組、專享消費組、通用消費組、非同步訊息重試消費組,topic同理也劃分為對等類別。透過細分consumer消費組和topic,定時觸發器業務和大流量業務隔離,正常業務和重試請求業務隔離,客戶的業務請求得到最高優先順序的保障。
- 安全容器隔離:傳統cce容器基於cgroup進行隔離,當客戶增多,客戶呼叫量變大時,會偶現客戶間的互相干擾。透過安全容器可以做到虛擬機器級別的隔離,客戶業務互不干擾。
邏輯多租服務,一旦升級出問題,造成的影響不可控。FunctionGraph支援按ring環升級(根據region上業務的風險度進行劃分)、藍綠髮布、金絲雀釋出策略,升級動作簡要描述成三個步驟:
- 升級前叢集的流量隔離:當前FunctionGraph升級時,優先將升級叢集的流量隔離,確保新流量不在進入升級叢集;
- 升級前叢集的流量遷移、優雅退出:將流量遷移到其他叢集,同時升級叢集的請求徹底優雅退出後,執行升級操作;
- 升級後的叢集支援流量按客戶遷入:升級完成後,將撥測客戶的流量轉發到升級叢集,待撥測用例全部執行成功後,在將正式客戶的流量遷進來。
當FunctionGraph出現系統無法兜住的錯誤後,我們給出的解決措施就是構建監控告警能力,快速發現異常點,在分鐘級別恢復故障,最大程度減少系統的中斷時間。作為系統高可用的最後一道防線,快速發現問題的能力至關重要,FunctionGraph圍繞著業務關鍵路徑,構建了多個告警點。如表2所示。
上面的一些措施從技術設計層面解決系統可用性的問題,FunctionGraph從流程上也形成了一套規章制度,當技術短期無法解決問題後,可以透過人為介入快速消除風險。具體有如下團隊運作規範:
- 內部war room流程:遇到現網緊急問題,團隊內部快速組織起關鍵角色,第一時間恢復現網故障;
- 內部變更評審流程:系統版本在測試環境浸泡驗證沒問題後,在正式變更現網前,需要編寫變更指導書,識別變更功能點和風險點,經團隊關鍵角色評估後,才准許上現網,透過標準的流程管理減少人為變更導致異常;
- 定期現網問題分析覆盤:例行每週現網風險評估、告警分析覆盤,透過問題看系統設計的不足之處,舉一反三,最佳化系統。
業界最先進的雲服務,對外也無法承諾100%的SLA。所以,當系統自身甚至人力介入都無法在急短時間內快速恢復系統狀態,這時候和客戶共同設計的容災方案就顯得至關重要。一般,FunctionGraph會和客戶一同設計客戶端的容災方案,當系統持續出現異常,客戶端需要針對返回進行重試,當失敗次數達到一定程度,需要考慮在客戶端側觸發熔斷,限制對下游系統的訪問,同時及時切換到逃生方案。
總結
FunctionGraph在做高可用設計時,整體遵循如下原則“冗餘+故障轉移”,在滿足業務基本需求的情況下,保證系統穩定後在逐步完善架構。
“冗餘+故障轉移”包括以下能力:
容災架構:多叢集模式、主備模式
過載保護:流控、非同步削峰、資源池化
故障治理:重試、快取、隔離、降級、熔斷
灰度釋出:灰度切流、優雅退出
客戶端容災:重試、熔斷、逃生
未來,FunctionGraph會持續從系統設計、監控、流程幾個維度持續構建更高可用的服務。如圖7所示,透過構建監測能力快速發現問題,透過可靠性設計快速解決問題,透過流程規範來減少問題,持續提升系統的可用效能力,為客戶提供SLA更高的服務。
圖7: FunctionGraph高可用迭代實踐
參考文獻
[1]高可用定義:https://zh.wikipedia.org/zh-hans/%E9%AB%98%E5%8F%AF%E7%94%A8%E6%80%A7
[2]SLA定義:https://zh.wikipedia.org/zh-hans/%E6%9C%8D%E5%8A%A1%E7%BA%A7%E5%88%AB%E5%8D%8F%E8%AE%AE
點選關注,第一時間瞭解華為雲新鮮技術~