作者 | Leonardo Creed
譯者 | 平川
策劃 | Tina
本文最初發布於 Engineer’s Codex 博客。
Meta 的無伺服器平台 XFaaS「每天要處理來自數十個數據中心區域的 10 萬多台伺服器上的數萬億次函數調用。」
XFaaS 是 Meta 內部的函數即服務(FaaS),類似於 AWS Lambda、Google Cloud Functions 和 Azure Functions 等公共 FaaS 選項。
我有幸提前讀到了他們就此撰寫的論文。
在命名方面,計算機科學家並不是很有創意,因為今年就有兩篇論文介紹「XFaaS」。一篇來自 Meta,另一篇來自 ISC Bangalore 的科學家。
兩篇論文介紹了兩個完全不同的系統,因此,如果用谷歌搜索「XFaaS」,則需要知道,本文討論的是該系統的 Meta 版本。
在命名方面,計算機科學家並不是很有創意,因為今年就有兩篇論文介紹「XFaaS」。一篇來自 Meta,另一篇來自 ISC Bangalore 的科學家。
兩篇論文介紹了兩個完全不同的系統,因此,如果用谷歌搜索「XFaaS」,則需要知道,本文討論的是該系統的 Meta 版本。
在這篇文章中,我將首先介紹要點內容和相關的經驗教訓,供那些想要了解大概情況的讀者參考。
然後,我將為那些想要深入理解 XFaaS 架構的讀者做更詳細的講解。
有趣的數據和結論
- 本文的一個重點是可以通過軟體來優化硬體利用率,從而提高無伺服器的性能。
- Meta 認識到,無伺服器函數的啟動開銷存在浪費,因此,他們希望通過模擬一個通用 worker 來消除這種浪費,即任何 worker 都可以立即執行任何函數而無需啟動開銷。
- 在這麼大的規模下,硬體成本非常高,每一個百分點都至關重要。
- XFaaS 僅用於非面向用戶的函數。無伺服器函數的延遲變化幅度比較大,無法提供穩定的面向用戶的函數。
- XFaaS 客戶端提交的函數調用請求存在很大的波動。峰值需求是非峰值需求的 4.3 倍還多。
- 他們提供的一個負載示例在 15 分鐘內向 XFaaS 提交了 2000 萬個函數調用請求。
- Meta 發現,尖峰函數的調用有其模式,藉此,他們設法使工作負載中的尖峰函數更可預測。
- 在這麼大的規模下,硬體成本非常高,每一個百分點都至關重要。
- 他們提供的一個負載示例在 15 分鐘內向 XFaaS 提交了 2000 萬個函數調用請求。
- Meta 發現,尖峰函數的調用有其模式,藉此,他們設法使工作負載中的尖峰函數更可預測。
XFaaS 的效率如何?
XFaaS 日均 CPU 利用率為 66%,遠遠優於行業平均水平。
不同區域中 worker 的 CPU 利用率
它利用時間(通過延遲函數調用)和空間(通過將其發送到負載較少的數據中心)有效地分散了負載。
Meta 正在將它們的許多函數安排到非尖峰時段,這樣負載和成本更可預測。
Meta 正在將它們的許多函數安排到非尖峰時段,這樣負載和成本更可預測。
因為是內部雲,所以 Meta 可以執行許多獨有的優化,例如,在同一進程中運行來自不同用戶的多個函數。
大多數函數不用一秒就可以完成,但並非全部如此。
XFaaS 解決的問題
問題:漫長的冷啟動時間
- 如果容器過早關閉,則下一次調用時就不得不再次初始化整個容器。
- 如果容器關閉得太晚,它就會處於閒置狀態,浪費寶貴的計算資源。
- 解決方案:XFaaS 使用即時編譯之類的方法來近似地實現每個 worker 都可以立即執行任何函數的效果。
問題:負載變化幅度大
- 資源配置過度導致硬體成本增加,或者資源配置不足導致系統速度較慢。
- 解決方案:XFaaS 將延遲容忍度低的函數推遲到非尖峰時段運行,並將函數調用分散到全球各個數據中心區域。
問題:導致下游服務過載
- 例如有一次,來自非面向用戶函數的調用激增,導致面向用戶的在線服務中斷。
- 解決方案:XFaaS 採用類似於 TCP 擁塞控制的機制來調節函數的執行。
與公有 FaaS(AWS Lambda、Google
Cloud Functions、Azure Functions)比較
- 公有雲 FaaS 會將函數執行限制在單個數據中心區域,而 XFaaS 可以全局調度函數調用,實現更好的負載平衡。
- FaaS 平台首要關注的是減少延遲,而忽略了硬體利用率。XFaaS 關注的則是硬體利用率和函數調用的吞吐量。
可供公有 FaaS 借鑑的經驗
以下幾項 XFaaS 技術可能會對公有雲有所助益:
- 允許調用者指定函數執行的開始時間。
- 允許函數所有者根據完成期限設置服務水平目標(SLO)(SLO 低則可以延遲到更好的時間段執行)。
- 允許函數所有者為函數設置緊急度。
雖然公有雲可能不會像 XFaaS 那樣在同一個進程中運行來自不同用戶的函數,但大型雲客戶可以在其虛擬私有雲中採用 XFaaS 方法。
少數幾個 Meta 團隊消耗了 XFaaS 很大一部分的容量。類似地,公有雲中的大客戶或許也可以受益於 XFaaS 的策略。
背景:前提和要求
從這裡開始,我將詳細介紹 XFaaS。
從這裡開始,我將詳細介紹 XFaaS。
正如前面提到的,XFaaS 需要應對尖峰負載。在需求高峰期,僅一個函數每分鐘就能收到 130 萬個調用請求。
前提
這裡有一個關鍵點是,大多數 XFaaS 函數都是由自動化工作流觸發的,可以接受延遲。前面已經說過,這使得 XFaaS 可以從時間(通過延遲函數的執行)和空間(通過將其發送到負載較少的數據中心)兩個角度來平衡負載。
XFaaS 支持 PHP、Python、Erlang、Haskell 運行時,以及一個適用於任何語言的基於容器的通用運行時。
函數的生命周期
函數有幾個開發者可以設置的屬性,如函數名、參數、運行時、緊急度、執行開始時間、執行完成期限、資源配額、並發限制和重試策略。執行完成期限的範圍從幾秒到 24 小時不等。
最後,XFaaS 在不同區域的硬體能力並不相同,因此負載平衡必須要考慮到這一點。
XFaaS 在不同數據中心區域的硬體容量並不均勻
工作負載類型
在 XFaaS 上,Meta 有三種類型的工作負載:隊列觸發的函數、事件觸發的函數(來自數據倉庫和數據流系統中的數據更改事件)和計時器觸發的函數(在預先設定好的時間自動觸發)。
函數分類
XFaaS 針對的是非面向用戶的函數,例如異步推薦系統、日誌記錄、生產力機器人、通知等等。
整體架構
XFaaS 架構概覽
客戶端通過向提交者發送請求來發起函數調用,提交者在將請求傳遞給 QueueLB(隊列負載均衡器)時會施加速率限制。
QueueLB 將函數調用保存到 DurableQ,在調用完成之前它會一直保存在那裡。
調度器會定期將這些調用移動到它的 FuncBuffer(內存中的函數緩衝區)中,並按緊急度、完成期限和資源配額對它們進行排序。
準備執行的調用會被移入 RunQ,然後 WorkerLB(工作負載均衡器)會將它們分配給合適的 worker。
客戶端通過向提交者發送請求來發起函數調用,提交者在將請求傳遞給 QueueLB(隊列負載均衡器)時會施加速率限制。
QueueLB 將函數調用保存到 DurableQ,在調用完成之前它會一直保存在那裡。
調度器會定期將這些調用移動到它的 FuncBuffer(內存中的函數緩衝區)中,並按緊急度、完成期限和資源配額對它們進行排序。
準備執行的調用會被移入 RunQ,然後 WorkerLB(工作負載均衡器)會將它們分配給合適的 worker。
提交者、QueueLB、調度器和 WorkerLB 都是無狀態、不分片的,並且複製時不指定領導者,因此,它們的副本都扮演相同的角色。
DurableQ 是有狀態的,它有一個分片的、高可用性的資料庫。
無狀態組件很容易擴展,只需要添加更多的副本即可。如果一個無狀態組件出現故障,它的工作可以直接由同級組件接管。
中央控制器和容錯機制
中央控制器與函數執行路徑是分開的。它們通過更新關鍵配置參數不斷優化系統。所謂關鍵配置參數是指那些供關鍵路徑組件(如 worker 和調度器)使用的參數。
這些配置會緩存在組件中,所以如果中央控制器出現故障,系統仍能正常運行(只是不能重新配置了)。
這樣,中央控制器停機 10 幾分鐘也不會導致什麼問題。這是 Meta 構建系統彈性的一個例子。
數據隔離
如果函數出於安全性或性能考慮需要強隔離,那麼它就會被分配到不同的命名空間。每個命名空間使用不同的工作者進程池來實現物理隔離。
由於對私有雲的信任、強制性同行評審和現有的安全措施,多個函數可以在單個 Linux 進程中運行。數據只能從較低的分類級別流向較高的分類級別。
提交者
客戶端向提交者發送調用請求。為了提高效率,提交者會批量處理這些調用請求,並通過一個操作寫入 DurableQ。
提交者通過一個分布式鍵值存儲來實現大型參數存儲,並內置了速率限制策略。為了處理客戶端提交速率的變化,區域為常規客戶端和高頻客戶端設置了兩個提交者集合。
XFaaS 會主動監視高頻客戶端,而限流或服務水平目標(Service Level Objective,SLO)的調節則需要人工干預。
QueueLB 和 DurableQ
然後,提交者向 QueueLB 發送函數調用請求。配置器(配置管理系統中央控制器)會根據 DurableQ 硬體容量的變化向 QueueLB 提供路由策略,以平衡不同區域的負載。
發送到 DurableQ 的調用請求會通過 UUID 進行分片,從而實現均勻分布。每個 DurableQ 根據調用者設置的計劃執行時間對函數調用進行分類和存儲。
調度器會不斷地查詢 DurableQ,從存儲的函數調用中查找到期的。當 DurableQ 將一個函數調用傳遞給調度器時,除非存在執行失敗的情況,否則它對調度器而言就是唯一的。
調度器與 DurableQ 的通信:
- 執行成功時發送一條 ACK 消息。然後函數調用就會從 DurableQ 中永久刪除。
- 執行不成功發送一條 NACK 消息。該函數調用會重新出現在 DurableQ 中,由另一個調度器處理。
調度器
調度器的主要作用是根據函數調用的重要性、截止日期和容量配額來確定它們的優先級。
它從 DurableQ 中獲取函數調用,將它們合併到 FuncBuffer 中(按重要性排序,然後是執行截止日期),然後將它們安排到 RunQ 中執行。FuncBuffers 和 RunQ 都是內存中的數據結構。
為了實現高效執行及防止系統延遲,RunQ 會對函數調用流進行控制。該系統還會保證負載均衡,Global Traffic Conductor(中央控制器)會根據需求和容量跨區域路由函數調用流,全面優化 worker 利用率。
WorkerLB 和 Worker
調度器的 RunQ 將函數發送到 WorkerLB(工作負載均衡器,在工作者進程池中運行函數)。
在 XFaaS 系統中,使用相同程式語言的函數是相互隔離性的,有專用的運行時和工作者進程池。
該系統的設計旨是使任何 worker 都能立即執行函數,而不會出現任何初始化延遲。XFaaS 會維護一個始終活躍的運行時,並保持本地 SSD 上的函數代碼最新。
通過協作式即時(JIT)編譯減少開銷
XFaaS 引入了協作式 JIT 編譯,定期將函數代碼打包推送給工作者,之所以要這樣做是因為代碼經常更新。
JIT 編譯有以下三個執行階段:
- 由幾個 worker 測試新代碼;
- 由 2% 的 worker 進一步測試代碼;有些執行 JIT 編譯性能分析;
- JIT 是在接收到函數調用請求之前完成,消除了延遲。
利用協作式 JIT 編譯,worker 在函數代碼更新後只需 3 分鐘就能達到每秒最大請求數,而不使用 JIT 編譯則需要 21 分鐘。
通過本地分組提高內存利用效率
因為存在內存限制,所以存儲每個函數的 JIT 代碼並不可行。
Locality Optimizer(中央控制器)將函數和 worker 劃分為組,確保需要大量內存的函數是分布式執行的。
使用本地分組減少了 11~12% 的內存消耗,並且可以保證 worker 高效、一致地使用內存。
工作者進程的內存利用率
XFaaS 如何有效地處理負載峰值
- 函數資源配額:每個函數都有一個配額,由其所有者設置,該配額定義了它每秒的 CPU 周期。該配額會轉換為每秒請求數(RPS)速率限制。中央速率限制器會根據函數的 RPS 限制確定是否限制函數調用。
- 時移計算:XFaaS 提供保留配額(用於快速執行)和機會配額(用於 24 小時內在低需求期間執行)。Utilization Controller 根據工作者利用率動態調整函數調用的速率。
- 函數動態 RPS 限制:為了防止下游服務負擔過重,XFaaS 使用類似 TCP 的 AIMD(Additive Increase, Multiplicative Decrease)方法動態調整 RPS 限制。它可以設置並發級別,並使用慢啟動方法管理 RPS 轉移。
我們過去遇到的一些挑戰,如 XFaaS 函數使 TAO 資料庫過載導致服務級聯故障,突顯了這些保障措施的必要性。現在,XFaaS 已經證明了其保護下游服務的能力,正如在真實事件中所看到的那樣,它的背壓機制提前抑制了潛在的過載,確保了服務的穩定性。
一己之見
這是一篇很棒的論文。Meta 向我們詳細介紹了他們的無伺服器平台,並為想要優化無伺服器函數使用方法的開發人員和公司提供了可供借鑑的經驗教訓。閱讀完整論文,請點擊這裡(可能需要機構訪問權限才能免費閱讀)。
此外,使用軟體優化硬體(例如 CPU 使用效率)在業界還沒有得到足夠的重視。雖然谷歌、Facebook 等公司針對自己的系統做了這樣的工作,但與軟體優化相比,人們對於這個話題的討論並不算多。
原文連結:
https://engineercodex.substack.com/p/meta-xfaas-serverless-functions-explained
瘋狂馬斯克的「極限」計劃居然成功了?!「下雲」後成本降低 60%,部分功能代碼精簡 90%,30 天急速遷移伺服器
程式設計師篡改 ETC 餘額,一年私吞 260 余萬元;語雀公布故障原因及賠償方案;各家財報發布,創始人們:就很難受|Q資訊
可部署手機、適配國產芯……全新升級後的 ChatGLM3 真的有點東西:智譜 AI 選擇繼續開源!
「這是一件關於雲服務的大事兒!」英特爾 4400 萬美元投資基礎設施初創公司,硬剛公有雲