K8s和YARN都不夠好,全面解析Facebook自研流處理服務管理平臺

Facebook在許多使用場景採用了分佈式流處理,包括推薦系統、網站內容交互分析等,這些應用的大規模實時運行需要達成嚴格的SLO。爲此,Facebook構建了新的流處理服務管理平臺Turbine,並在生產系統中上線運行近三年,部署在由數萬臺機器構成的集羣中,管理着數千條流水線,每秒實時處理數以TB的數據。在Facebook的生產經驗證明,Turbine很好地平衡了羣集間的工作負載波動,可預測計劃之外的負載峯值,持續高效地完成大規模處理。

近十年來,大規模分佈式流處理得到廣泛應用,並形成了多個成熟的生產系統,各自專注於不同領域的挑戰,例如故障容忍(Apache Storm)、低延遲(Apache Flink、Storm),可操作性(Twitter Heron)、直觀編程模型(Millwheel)、語義處理(Dataflow、Samza、Flink)、彈性伸縮(Millwheel),有效資源管理(Twitter Heron)和狀態管理(Spark Streaming)等。

Facebook也面臨着同樣的需求。該公司的許多應用採用分佈式流處理,包括網站內容的低延遲分析互動、搜索效果分析和推薦系統等應用場景。爲了滿足這些需求,Facebook爲開發人員構建了使用類SQL聲明式流處理開發語言和C++/Python/PHP命令式開發API的框架,並使用該框架構建了大量無狀態和有狀態的流處理應用。這些應用需要一個可擴展的流處理服務管理平臺實現規劃、配置和部署,並確保應用的停機時間和處理延遲等指標,即便在停機和負載波動的情況下也能滿足嚴格的SLO。FB的很多流處理應用程序要求90秒的端到端延遲閾值。

現有的通用集羣管理系統,例如Aurora、Mesos、Borg、Tupperware和Kubernetes等,雖然可以在一定程度上滿足跨多種負載的通用管理要求,但並不適用於Facebook的流處理需求。其中,Borg是由多個異構系統組成的生態,用戶必須瞭解多種各不相同的配置語言和流程,才能配置系統並與其交互。Kubernetes基於Borg的經驗,改進了分佈式服務部署和管理體驗。YARN資源管理器得到了Flink、Samza、Spark Streaming和StreamScope等流處理系統的採用。這些管理系統雖然大都實現了有效的資源隔離和執行框架,但是需要提前確定所需的處理資源才能高效運作,這在流處理場景中是很難做到的。此外,這些系統並不能很好地支持資源的自動縮放。

本文闡述了Turbine的架構設計考量及實現,內容來自論文“Turbine: Facebook’s Service Management Platform for Stream Processing”。該論文已被2020 ICDE會議工業系列(Industry Track)錄用,第一作者Yuan Mei本科畢業於北京大學,在MIT獲得博士,現任Flink架構師。

概述

Turbine是Facebook的可擴展流處理服務服務管理平臺,解決了現有通用集羣管理框架難以適應Facebook流處理需求的問題。Turbine已上線Facebook生產環境近三年,很好地支持了Facebook的衆多流處理應用。

Turbine的創新之處在於實現了快速且可擴展的任務計劃調度,支持自動縮放的資源有效預測機制,並提供滿足容錯、原子、一致、隔離和持久性(ACIDF,atomic,consistent,isolated,durable and fault-tolerant)的更新機制。具體而言:

  • 調度機制使用兩級調度機制,實現流處理任務的配置和管理。調度器首先使用Facebook的通用分片管理器將分片置於指定容器中,然後使用哈希機制將流處理任務分配給分片。每個分片會定期進行負載平衡,並且Turbine提供了負載平衡時重新計劃流處理任務的安全調度機制。爲確保故障不會導致數據損壞、丟失或重複處理,Turbine實現了容錯機制。
  • 自動縮放機制可自動調整CPU,內存,磁盤等維度上的資源分配。爲達成設定的SLO目標,自動縮放機制估算指定流處理作業所需的資源,然後按比例放大或縮小流處理任務的數量,以及每個任務所分配的資源。自動縮放機制還可根據這些資源縮放決策和歷史工作負載,對原始資源估算情況迭代地做出調整。
  • 提供滿足ACIDF的應用更新機制。對於流處理服務管理,更新機制非常重要,因爲服務提供者、資源自動縮放和人工操作等處理參與者可能會同時更新同一流處理作業。系統必須確保所有更新相互隔離,並滿足一致性。爲此,Turbine設計了分層作業配置架構,基於作業優先級對多個參與者的更新操作進行合併。Turbine通過計劃更新與實際更新的分離,提供了支持ACDIF的更新機制。更新機制使用狀態同步服務,實現預期和運行作業配置間的同步,並支持更新失敗時做回滾和重試。

Turbine採用鬆耦合的微服務設計,實現作業管理、任務管理和資源管理,架構了一種高度可擴展且具有彈性的管理平臺,滿足應用的SLO需求,支持在無人工監督情況下的海量數據流處理。

Turbine整體架構

Turbine的架構如圖1所示。應用開發人員使用API以聲明式和命令式編程方式構建數據處理流水線應用,支持下至基本的過濾和投影操作、上至具有多個連接和聚合運算的複雜圖關聯查詢。查詢在通過模式檢查等合規性檢查後,被編譯爲Turbine的內部表示形式,優化後發送給Turbine處理引擎。引擎負責生成運行時配置文件,支持以批處理和流處理兩種模式執行應用。批處理模式主要適用於從數據倉庫處理歷史數據的應用場景,本文主要介紹流處理模式。

圖1 Turbine整體架構圖

Turbine流處理系統包括作業管理、任務管理和資源管理三大主要組件。處理流水線由多個作業組成,每個作業具有多個可並行執行的任務,每個任務獨立處理部分流數據。作業管理存儲作業的配置,並維護作業的更新。任務管理將作業配置分解爲獨立任務,在集羣上調度任務執行並維護負載均衡。資源管理實時分配集羣、作業和任務資源。Turbine在設計上很好地解耦了各組件間的決策關聯,任何組件產生的失敗均可通過處理降級模式得到解決,不會影響整體操作的繼續執行。

在數據模型設計上,Turbine作業間的通信採用Facebook自研的消息持久化總線Scribe實現。每個任務從Scribe讀取一到多個數據獨立分區,維護自身的處理狀態和檢查點,在處理失敗時從Scribe分區讀取數據和檢查點信息以恢復任務。這種數據模型設計簡化了任務依賴,使得系統在任務調度、負載均衡和資源擴展中無需考慮任務間的依賴關係。

作業管理

流處理中,每個應用都被編譯並優化分解爲一組獨立執行的作業。作業執行所需的所有配置和信息由作業配置維護。作業在執行期間,作業配置會因爲用戶操作以及內部其它服務的需求而發生變更。因此,作業管理的一個重要挑戰,就是如何確保配置變更符合ACIDF要求。符合ACIDF對於作業變更而言非常重要,因爲在運行環境中可同時存在上萬個作業,變更可能會導致作業執行失敗,甚至是相互衝突。作業管理必須實現作業的自動變更、擴展和溯源。

基於此需求,Turbine作業管理在設計上包括:實現配置管理的作業存儲(Job store)、自動提交配置更改的作業服務(Job servie),以及執行作業配置更改的狀態同步(state syncer)。

作業資源配置:出於對作業配置獨立性和一致性的考慮,Turbine採用了一種層次化的作業配置結構。配置管理使用Thrift實現編譯時類型檢查,並由Thrift JSON序列化協議將配置轉換爲JSON表示。這樣的層次化配置結構設計,支持整合來自不同服務的任意數量的配置需求,並通過JSON文件的歸併實現統一邏輯的層次化疊加。

具體而言,Turbine對需執行的作業定義了一個期望配置,基於此在作業執行時生成一個運行配置。在期望配置中,包括了定義作業基本資源的基礎配置、定義更新資源的預定配置、定義自動擴展資源的擴增配置,以及定義用戶手工操作作業所需資源的待定配置。層次化資源定義實現了上述四類配置的相互隔離,爲作業執行提供一致的狀態視圖。

作業狀態同步:爲實現作業更新的原子性、持久性和容錯性,Turbine實現了期望配置和運行配置的獨立存儲,並通過狀態同步實現二者間的同步。每一輪作業執行時,狀態同步按配置優先級依次歸併各個層級的期望配置,並將生成配置與運行配置比較。一旦存在差異就生成新的執行計劃,並提交執行。在同時運行上萬個任務的大規模集羣中,任務出於負載均衡的考慮會在主機間遷移,上述同步操作機制可確保作業的原子性、容錯性和持久性。

爲提高同步操作的性能,狀態同步會對基本的同步操作執行批處理,並對複雜的同步操作做並行化處理。

任務管理

任務管理主要負責任務調度、負載均衡和故障處理。Turbine通過集成Facebook自研的容器管理器Tuppperware,實現Linux容器的分配和編排。每個容器運行一個自身的任務管理器,負責在當前容器中運行的流處理任務。

圖2 兩層分佈式任務調度和負載均衡

任務調度:Turbine使用Facebook的分片管理器(類似於Google Slicer),實現對容器的均衡資源分片。Turbine設計了兩層資源調度機制,如圖2所示。資源調度將計算資源物理分配給各個容器。圖中的四個分片將被指派給三個容器,每個任務管理器從任務服務(Task Service)獲取任務描述的完整快照,並調度分片所指派的任務。在任務調度實現中,需考慮任務與分片的映射關係維護,以及分片的混洗和重新分配機制。

負載均衡:在任務調度完成初始的“分片-容器”指派後,任務管理器依據該指派啓動任務。在任務運行期間,Turbine週期性輪詢分片負載情況,並根據情況由分片管理器做混洗和重新分配。具體而言,每個容器指定了內存、CPU等資源數量,每個分片指定了可承擔的負載量。分配算法根據二者匹配情況及總體資源使用情況,採用裝箱類算法計算得到指派。這裏的一個重要問題,是如何定義分片負載。Turbine通過採集多種度量,綜合定義多個層級的資源保障,以改進集羣的整體資源使用效率。例如,對於C/C++任務,系統採集固定時間窗內的平均內存使用情況;而對於使用cgroup管理的JVM任務,則採集xmx、cgroup限額等峯值資源需求。度量採集使用一個後臺的負載聚合線程,實現對當前資源使用情況的實時估算。

故障處理:故障處理的主要目的是降低系統運行故障對任務運行的影響,確保任務失敗不會對數據本身產生破壞。爲此,Turbine在分片管理器中引入了一種基於心跳的雙向故障轉移協議。一旦分片管理器在設定時間(默認爲60秒)內沒有接收到來自任務管理器的心跳,就認爲相應的容器已經停止工作,進而爲該容器中的分片重新進行指派,並啓動上面介紹的分片遷移機制。需要注意的是,網絡連接故障等情況也會導致心跳停止。這時如果直接遷移分片,會導致重複的分片指派,進而導致重複的數據處理。針對此類問題,Turbine進一步設計了一種主動超時機制。一旦連接超過了設定的超時時間(通常小於心跳時間,默認爲40秒),那麼Turbine容器就會重啓,並在重啓後重新連接分片管理器,恢復故障轉移前的分片狀態。

綜上,下列設計確保了Turbine實現任務高性能調度和任務的高可用性:

  • 如圖2所示的兩層資源調度架構,實現了任務調度和資源調度的分離。
  • 任務管理器完全掌控任務列表,這樣即便在任務服務和作業管理失效的情況下,Turbine依然可執行負載均衡和故障遷移。
  • 定期更新的任務管理,確保任務更新情況能及時反映給任務管理。在Facebook大規模集羣的實際運行中,狀態同步延遲平均維持在1至2分鐘以內。
  • 一旦系統出現故障,可在60秒內完成故障遷移。任務的平均宕機時間控制在2分鐘以內。

彈性資源管理

資源管理根據任務、作業和集羣的負載情況,對資源使用做出動態調整。資源管理一方面可確保所有作業具有足夠的資源以按時完成輸入處理,另一方面確保有效利用整個集羣中的資源。Turbine資源管理在借鑑現有系統一些好的做法的同時,充分考慮瞭如何降低系統中無必要的資源消耗,例如避免重啓不需要重啓的任務。

最初,資源管理器採用響應式機制,即通過監測任務滯後和積壓、輸入不平衡、任務運行內存不足(OOM)等預設問題,並採取響應資源管理操作。這種機制雖然在流處理系統中普遍使用,但在Fcebook生產環境中出現了一些問題。首先,由於對作業所需資源缺乏準確預估,一些時候會導致某一作業等待特定資源而耗時過長。其次,由於缺乏對資源需求下限的判定,因此無法保證作業每次都能健康運行,進而導致作業積壓問題。第三,缺乏對導致問題最根本原因的洞察,會導致問題的進一步擴大。

基於Facebook的運行實踐,大多數固定任務所需的資源數量通常是可預測的。只要應用的邏輯和配置不變,那麼任務的資源佔用情況也是具有固定模式的。基於這一觀察,Turbine設計了一種主動預測機制。採用此機制的資源管理架構如圖3所示。架構設計上由資源預估(Resource Estimator)、執行計劃生成(Plan Generator)和模式分析(Pattern Analyzer)組成。

圖3 Turbine資源管理器架構

資源預估:對給定作業的資源使用情況作出預估。作業可根據處理狀態看分爲兩類,即過濾、投影、轉換等無狀態作業,以及連接和聚合等有狀態作業。無狀態作業一般是CPU密集型操作,例如輸入反序列化、數據處理和輸出序列化等,CPU的消耗情況通常與數據輸入輸出的規模成正比。由此,可以通過對輸入輸出的度量,判定單個線程的最大穩定處理率,進而預估CPU資源。有狀態作業在CPU資源之外,還需要預估內存和磁盤的使用情況。其中,聚合運算的內存需求與輸入數據的規模成正比,而連接運算的內存和磁盤需求與輸入項的笛卡爾積規模以及結果的選擇率相關。

模式分析:任務在動態增加、移除或重啓時,其初始化通常需要耗費大量CPU和I/O資源。資源管理器必需考慮此因素,以免初始化操作造成整個集羣運行不穩定。爲此,Turbine引入了模式分析,根據現有的數據情況推測資源的佔用模式,防止出現可能導致集羣不穩定的潛在隱患。模式分析需要記錄並分析資源調整情況和歷史工作負載模式,確保在資源擴展中不會發生頻繁更改資源分配的情況。

容量管理:考慮到Facebook數據中心分佈在全球範圍,容量管理可臨時授權不同的數據中心集羣間進行資源交換,以達到全球範圍內資源的有效使用。容量管理監測集羣中作業的資源使用情況,確保在集羣範圍內各類型的資源得到合理分配。

生產環境實測

本文以Scuba Tailer流處理應用爲用例,展示Turbine生產系統的運行情況。Facebook Scuba提供時序數據的實時即席查詢,主要適用於實時性能問題診斷、處理結構改進影響分析等場景。Scuba Tailer流處理應用從Scribe讀取輸入數據、處理並將結果返回Scuba後端。該應用運行在一個專用的處理集羣上。集羣中包括位於三個備份區域的兩千多臺服務器,每臺服務器具有256GB內存,48至56個CPU內核。每個任務的CPU佔用與數據量近乎成正比,內存佔用與消息平均大小近乎成正比。圖4顯示了近12萬個任務的負載特性。可見約80%的任務佔用不到一個CPU線程,而每個任務需佔用近400MB存儲資源,而99%的任務存儲資源佔用低於2GB。

圖4 Scuba Trailer任務的CPU和內存使用統計情況

負載均衡

如前所述,Turbine監測所有運行中任務的資源佔用情況,並將任務調度到所有可用的機器上。圖5(a)和(b)顯示了Tailer集羣一週時間期內的CPU和內存使用情況。圖5(c)顯示Turbine很好地在機器間分發任務,每個機器的任務數變化範圍控制在150~230小範圍內。在Turbine上線前,每個Scuba Tailer使用獨立的容器運行。Turbine更好地利用了各容器中的碎片化資源,實現了整體資源佔用降低約33%。

圖5 在600多臺機器的Tailer集羣中,各機器的CPU和內存使用近乎平均。每臺機器維持數百量級的任務運行,其預留資源足以應對輸入數據流的突發尖峯。

負載變更響應

Turbine自動執行資源擴展,確保所有作業具有足夠資源,並且整個集羣的資源得到有效使用。

圖6顯示了一個任務層面的變更用例。其中,Scuba Tailer任務由於應用問題禁用了五天,導致數據積壓。在應用重新上線後,需要儘快重新處理積壓數據。圖中紫色曲線顯示資源管理將任務擴增到任務上限32個,並在手工移除上限後擴增到128個。與之相對比,沒有使用Turbine的cluster2集羣在兩天後才處理完所有積壓任務。

圖6 Turbine資源自動擴展有助於積壓任務的快速恢復

圖7顯示了一個集羣層面的變更用例。Facebook會定期演練災難恢復,將某個數據中心完全斷開連接,該數據中心的所有流量會重定向到另一個數據中心。Turbine在其中起到重要作用,負責擴展健康可用數據中心的作業資源。圖7顯示了集羣任務總數在演練中的變化情況,數據中心斷開發生在第二天的早晨,圖中紫色曲線整個集羣流量相比正常情況峯值增加了約16%,而總任務數增加了約8%。這是由於Turbine優先考慮做垂直擴展,而非水平擴展。在演練期間及前後,約99.9%的作業能保持SLO。

圖7 Turbine在災難恢復演練期間的水平擴展情況

總結

近十年間,大規模分佈式流處理在多個關鍵行業得到廣泛應用。爲解決迅速增長的流處理需求所提出的挑戰,需要實現高度可擴展且高度彈性的流處理架構。這也同樣是Facebook在生產中面對的問題。Facebook的許多用例採用分佈式流處理來獲取所需數據,包括推薦系統、網站內容交互分析等,這些應用的大規模實時運行需要達成嚴格的SLO。

Turbine已在生產系統中上線運行近三年,部署在由數萬臺機器構成的集羣中,管理着數千條流水線,每秒實時處理數百GB的數據。在Facebook的生產經驗證明,Turbine很好地平衡了羣集間的工作負載波動,可預測計劃之外的負載峯值,持續高效地完成大規模處理。

原文鏈接: 
Turbine: Facebook’s Service Management Platform for Stream Processing

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章