Meta 的 Serverless 平臺挺強的
XFaaS 是 Meta 爲內部使用而開發的函數即服務(FaaS)系統,它與像 AWS Lambda、Google Cloud Functions 和 Azure Functions 這樣的 FaaS 平臺有很多相似之處。
我很幸運提前看到了他們關於這個主題的論文。
計算機科學家在命名上似乎並沒有太大創意,因爲今年有兩篇介紹 XFaaS 的論文。一篇是 Meta 的,另一篇是由 IISC Bangalore 的科學家所寫。
這兩套系統截然不同。因此,當你在 Google 上搜索 “XFaaS” 時,就知道這篇論文是描述 Meta 的系統版本。
在這篇文章裏,我首先給出了一些高屋建瓴的總結和啓示,適合那些想要快速瞭解的讀者。
接着,我會更詳細地解讀論文,幫助那些想要理解 XFaaS 背後架構的讀者。
#01
有趣的數據和核心觀點
-
論文強調了一個核心觀點:通過軟件優化,可以更高效地利用硬件,從而提升無服務器計算的性能。
-
Meta 公司明確指出了無服務器函數在啓動時的過高開銷問題,並計劃採用一種 “通用工作模式”。這意味着任何工作節點都能立即執行任意函數,而不需要額外的啓動時間。
-
在大規模操作下,硬件的成本非常高,因此每一點的優化都顯得尤爲重要。
-
**XFaaS 僅被用於非直接面向用戶的函數。**因爲無服務器函數的延遲變化太大,所以它們並不適合直接用於用戶交互的功能。
-
使用 XFaaS 的客戶提交的函數調用具有高度的突發性。其中,高峯期的需求是平常需求的 4.3 倍。
-
他們展現了一個實例,在短短 15 分鐘內,有 2000 萬的函數調用請求被提交到 XFaaS。
-
Meta 發現,儘管某些功能的調用具有很大的波動性,但仍存在一定的規律。公司利用這些規律來使得功能的調用在工作負載上更爲穩定。
XFaaS 的效率如何?
XFaaS 的日均 CPU 利用率達到了 66%,這明顯高於行業的平均水平。
通過在時間上延遲功能和在空間上選擇負載較低的數據中心,它高效地分散了負載。
Meta 正在逐步將更多功能轉移到非高峯時段執行,使負載和成本更爲穩定。
由於它是內部雲服務,Meta 可以進行很多獨特的優化,例如在同一個進程中爲不同的用戶運行多個功能。
大多數功能執行時間都不到一秒,但也有例外。
XFaaS 解決了哪些問題?
問題 1:冷啓動時間過長。
如果容器過早關閉,下次調用需要重新初始化整個容器;而如果過晚關閉,則會空閒浪費資源。
解決方案:XFaaS 採用即時編譯等技術,確保每個工作器都能即刻執行任何功能。
問題 2:負載的高差異性。
這會導致由於過度配置造成過多的硬件成本,或者在配置不足時導致系統速度下降。
解決方案:XFaaS 將容忍延遲的功能推遲到非高峯時段運行,並在全球的數據中心分散函數調用。
問題 3:下游服務的過度負載。
例子:曾有一次,非面向用戶功能的大量調用導致面向用戶的在線服務出現故障。
解決方案:XFaaS 採用與 TCP 擁塞控制類似的機制來調整功能的執行。
與公有云 FaaS 的對比
-
公有云 FaaS 只能在單一的數據中心區域執行,而 XFaaS 能全球分配功能調用,實現更優的負載均衡。
-
其他 FaaS 平臺首先考慮降低延遲,而 XFaaS 重視硬件利用率和功能調用的吞吐量。
XFaaS 爲公有云帶來的可能優勢:
-
允許調用者設置功能執行的起始時間。
-
允許功能所有者爲完成時間設定服務級別目標(低優先級的可以選擇在更合適的時間延遲執行)。
允許功能所有者爲功能設置重要性級別。
儘管公有云可能不會像 XFaaS 那樣在同一進程中爲不同用戶執行功能,但大型雲客戶可以在其私有云中採納 XFaaS 方法。少數幾個 Meta 團隊已佔據了 XFaaS 的大部分容量,公有云中的大客戶也可能從 XFaaS 的方法中受益。
#02
背景:基礎設定和需求
這是對 XFaaS 詳細概覽的開始。
正如之前提到的,XFaaS 處理的負載有很大的波動性。在高峯時段,一個功能可能會在一分鐘內接收到 130 萬次的調用。
基礎設定
最關鍵的一點是,XFaaS 的大多數功能是由自動化流程觸發的,這些流程對於延遲是可以接受的。這樣,XFaaS 就可以通過時間(通過延遲功能的執行)和空間(將任務發送到負載較低的數據中心)來平衡負載。
XFaaS 支持多種運行時環境,包括 PHP、Python、Erlang、Haskell,以及爲各種語言設計的基於容器的通用運行時環境。
開發者可以爲函數設置多個屬性,如函數名稱、參數、運行時、關鍵性、執行開始時間、完成時間限制、資源配額、併發限制和重試策略。執行完成的期限可以從幾秒到 24 小時。
最後,由於 XFaaS 在不同的區域有不同的硬件容量,因此在進行負載均衡時必須考慮這一點。
工作負載類型
Meta 在 XFaaS 上有三種工作負載:由隊列觸發的函數、由數據變更事件(在數據倉庫和數據流系統中)觸發的事件函數,以及定時函數(根據預設的時間自動觸發)。
XFaaS 主要用於不直接面向用戶的功能,例如異步推薦系統、日誌、效率提升機器人、通知等。
#03
總體架構
當客戶端想要發起函數調用時,它們首先會發送請求到 “提交器”(submitter)。提交器會首先應用速率限制,然後將請求傳遞給 QueueLB(隊列負載均衡器)。
QueueLB 的任務是將這些函數調用指引到 DurableQ 中,以存儲直至它們完成。
隨後,調度器週期性地從 DurableQ 中取出這些調用,將其移至其 FuncBuffer(內存中的函數緩衝器),並根據它們的緊迫性、截止日期和配額對它們進行排序。
那些準備執行的調用會被移動到 RunQ 中,而 WorkerLB(工作負載均衡器)則會將它們分配給合適的工作節點。
這些組件,如提交器、QueueLB、調度器以及 WorkerLB,都是無狀態的、無分片的,同時也是複製的,且它們沒有指定的領導者,這意味着它們的每一個複製都有相同的功能。
DurableQ 則是有狀態的,並且具有一個分片的、高可用性的數據庫。
增加更多的複製可以輕鬆地擴展一個無狀態的組件。如果一個無狀態的組件出現故障,其工作可以輕鬆地被其他同級組件接管。
中央控制器與容錯
中央控制器與函數的執行路徑是分離的。它們持續地對系統進行優化,更新關鍵配置參數,這些參數被像工作節點和調度器這樣的關鍵路徑組件所使用。
這些配置信息是被緩存在各組件內的,所以即使中央控制器出現故障,系統也能夠正常運行(但是它就不能再被重新配置了)。
這意味着,中央控制器可以停機長達幾十分鐘。這展示了 Meta 如何爲該系統增加彈性。
數據隔離
那些出於安全或性能原因需要強烈隔離的函數,會被分配到不同的命名空間。每一個命名空間使用獨立的工作池來達到物理隔離。
多個函數可以在同一個 Linux 進程中運行,這得益於私有云內的信任機制、強制的代碼審查以及其他的安全措施。數據只能從低級分類流向高級分類。
提交器(Submitter)
客戶端向提交器發送函數調用請求。爲了提高效率,提交器通過批處理這些調用並將它們統一寫入 DurableQ。
提交器通過分佈式鍵值存儲來管理大量的參數,並內置了速率限制策略。由於客戶端提交速率的差異,各區域設置了兩組提交器:一組面向常規客戶,另一組面向高頻客戶。
XFaaS 對高頻客戶進行了積極監控,並在進行節流或服務水平目標(SLO)調整時需要人爲干預。
隊列負載均衡器(QueueLB)與 DurableQ
函數調用從提交器傳輸到 QueueLB。Configerator(中央配置管理系統控制器)爲 QueueLB 提供路由策略,以在各區域之間平衡負載,因爲不同區域的 DurableQ 硬件容量不同。
DurableQ 使用 UUID 來分片函數調用,確保均勻分配。DurableQ 根據調用者設置的執行時間將函數調用進行分類和存儲。
調度器持續從 DurableQ 中查詢即將到期的函數調用。一旦函數調用被 DurableQ 交給調度器,除非執行失敗,否則它會獨佔該調度器。
調度器與 DurableQ 之間的交互如下:
-
對於成功執行的調用,調度器發送 ACK 消息。此後,該調用將從 DurableQ 中被永久刪除。
-
對於執行失敗的嘗試,調度器發送 NACK。這樣,該函數調用會重新在 DurableQ 中變得可用,等待另一調度器進行處理。
調度器
調度器的核心任務是基於它們的重要性、截止時間以及配額來對函數調用進行排序。
它從 DurableQ 中提取函數調用,然後將它們整合到 FuncBuffers 中(首先按重要性排序,然後按執行截止時間),隨後再將它們排入 RunQ 以待執行。FuncBuffers 和 RunQ 都是內存中的數據結構。
爲了管理高效的執行並避免系統滯後,RunQ 控制函數調用的流向。系統還確保了負載均衡,通過全球流量導向器(中央控制器)根據需求和能力跨地區指導函數調用流量,確保了整體的工作負載平衡。
WorkerLB 和 Worker
調度器的 RunQ 會將函數傳遞給 WorkerLB,它隨後再由工作器池中的工作器運行。
在 XFaaS 系統中,使用同一種編程語言的函數會被隔離,並且具有專用的運行時及工作器池。
該系統的設計意圖是確保任何工作器都能立即執行函數,無需任何啓動延遲。XFaaS 始終保持一個活躍的運行時環境,並確保工作器的本地 SSD 上的函數代碼始終是最新的。
合作的即時編譯(JIT)以降低開銷
XFaaS 引入了合作式即時編譯,週期性地將函數代碼打包並傳送給工作器。由於代碼經常更新,因此這一步驟是必要的。
JIT 編譯包含三個執行階段:
-
少數工作器測試新代碼。
-
2% 的工作器進一步測試這些代碼,並有一些進行 JIT 編譯的性能分析。
-
在接受函數調用前完成即時編譯,從而避免了延遲。
使用合作的即時編譯,一個工作器在函數代碼更新後的 3 分鐘內達到其最大請求率,而如果沒有使用 JIT 編譯,則需要 21 分鐘。
局部組以實現高效的內存使用
由於內存限制,存儲每個函數的 JIT 代碼是不現實的。
局部優化器(中央控制器)將函數和工作器分組,以確保內存密集型的函數得到合理分配。
通過使用局部組,內存使用率降低了 11-12%,這也使工作器能夠更加高效且穩定地利用內存。
如何有效地處理 XFaaS 的負載峯值
-
函數配額:每個函數都有一個配額,該配額由其所有者確定,並定義了其每秒的 CPU 循環。此配額進一步被轉化爲每秒請求(RPS)的限制。中央速率限制器基於函數的 RPS 上限來判斷是否進行節流。
-
時間位移計算:XFaaS 提供了預留的(用於立即執行)和機會性的配額(在 24 小時內的低需求時段執行)。利用控制器根據工作負載使用情況動態地調整函數調用速率。
-
函數的動態 RPS 限制:爲了不給下游服務帶來過大負擔,XFaaS 採用了類似 TCP 的 AIMD(加性增加,乘性減少)策略來動態地調整 RPS 上限。它可以調整併發水平,並採用漸進啓動方法來管理 RPS 的變化。
以前,如一個 XFaaS 函數過載了 TAO 數據庫,導致了一系列的服務失敗,這突顯了這種防護措施的必要性。現在,正如實際事件中所見,當其背壓機制預先遏制了潛在的過載時,XFaaS 成功地保護了下游服務,確保了服務的穩定。
#04
我的看法
這是一篇卓越的論文。Meta 爲我們深入展示了他們的無服務器平臺,同時爲開發者和希望優化自己無服務器功能使用的公司提供了寶貴的經驗。
論文鏈接:
https://dl.acm.org/doi/abs/10.1145/3600006.3613155
另外,如高效的 CPU 使用這樣的硬件優化在業界並沒有得到足夠的重視。雖然像 Google、Facebook 這樣的公司在他們自己的系統上這樣做,但與軟件優化相比,這並不是一個常被提及的話題。
同時,如果你對其他實際應用的分佈式系統感興趣,我還寫了一篇關於 Meta 如何通過建立世界上最大的 Memcached 系統來處理每秒數十億次的請求。
文章鏈接:
https://engineercodex.substack.com/p/how-facebook-scaled-memcached
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/M2fN81frQLlJpBWq-lWQ_Q