聊一聊實時計算系統設計

AIOps智慧運維發表於2018-12-11

作者簡介:餓馬搖鈴    百度雲高階研發工程師

負責百度雲智慧運維產品(Noah)資料採集和計算方向架構設計和研發工作,對分散式系統架構有一定實踐經驗。


乾貨概覽

本文是我在實時資料計算系統的設計、開發、運維生涯的一部分經驗總結。主要介紹一些設計思路和常見問題的解決方案,不關注具體計算框架的使用。

本人主要致力於監控系統資料計算方向,主要業務場景有:監控資料的ETL、資料匯聚、分析、異常檢測等。由於監控系統對時效性有較高需求,所以我們的計算系統更偏向實時系統,根據業務場景的不同,延遲從數百毫秒到分鐘不等。下文提到的計算架構更多是指整個計算處理通路,主要以監控場景下的系統設計為例,相信與其他場景下的架構也有相通之處。

文章從以下幾個方面展開。

首先,在第1節,我們簡述不同資料規模和場景下,監控系統計算架構的可選方案。在公司、業務發展的不同階段,主要矛盾不同,能夠投入人力物力資源不同,需要選擇合適的架構方案。

實時計算系統的設計有一個核心問題:如何同時滿足高時效性和資料準確性?在現實環境中,高時效性和準確性很難同時達到,第2節中介紹了Watermark機制以實現兩者的平衡。

第3節介紹百度監控系統的實時計算系統架構,描述了其基本組成、思路和實現中一些常見問題的解決方案。

最後,簡單討論了實時計算系統可用性建設

監控系統計算架構選型

對於包含數百到千級別節點的小叢集,資料規模有限,所有采集、儲存、計算邏輯都可以整合在一個模組中實現,這種多為領域專用系統。監控系統中,典型的有Prometheus,其採用單服務節點架構,提供簡單的HA模式進行容錯,這種架構的優點是部署使用簡單。受限於單機資源,適合部署自治的多個例項,每個例項監控不同服務。大規模叢集情況下,要實現全域性的監控,需要合併多個監控例項的資料,在配置分發、可用性、容錯、自動化部署管理等方面都需要更多的工作。從開發角度考慮,由於功能耦合嚴重,不利於開發升級。

比起領域專用系統,還有一種架構是使用通用性更強的OLAP系統來實現實時或者近實時的計算功能,如TSDB、ElasticSearch等系統都有一定的聚合計算能力。這些分散式系統都有水平擴充套件能力容錯能力,但難以實現複雜業務計算,同時延遲不可控,複雜查詢或大批次資料查詢的延遲可能會達到分鐘級別。

更多的情況下我們採用儲存計算分離的方案,以便儲存和計算的各自演進和平臺化。通常由一個提供精細查詢能力的儲存服務與一個計算模組組成。計算模組根據計算規則從儲存系統中拉取資料並進行計算,這個架構的瓶頸在於儲存系統能夠支援的查詢規模。根據我們的經驗,基於精心設計的記憶體資料庫叢集,能夠承受百萬級別的併發查詢。這種架構下計算任務多為週期性排程,當查詢效能下降時會造成任務的堆積。這個模型不方便處理延遲資料,需要一定機制預測資料完整時間,排程任務進行重算,任務排程的複雜度高。基於索引查詢的計算系統的延遲取決於計算輪詢的週期,適用於聚合類的涉及時間視窗的運算操作。

更高資料量和計算規則的情況下,流式計算是一個自然的選擇,降低了寫儲存、索引、查詢的消耗,計算延遲大幅降低。

當資料量進一步上升,需要的網路吞吐、計算能力驟增,後端的算力難以跟上資料量的增長。這時候可以將計算能力分散到全鏈路,將計算提前到資料產生端。在監控系統中,透過在採集端進行預計算和ETL操作,提取或整合有用資訊,對於實時日誌採集,能大幅度降低傳輸到後端的資料量。放到更大的視角上,這種將算力下放到資料來源的思想,是目前大熱的邊緣計算的一個主要思路。

近年來,以AWS Lambda為首的Serverless計算架構得到了更多的重視。這個模型將計算抽象為事件以及觸發的計算邏輯,計算邏輯實際由框架排程、分配資源執行。使用者只需要編寫計算邏輯,而不用關心可用性、可擴充套件、負載均衡等後端程式碼,極大的降低了開發成本。透過按需排程,自動擴縮容,業務運維方不再關心容量規劃等問題。私以為當前常見計算框架的Serverless化是一個值得嘗試的方向。目前的Serverless框架還存在很多問題,例如排程初始化虛機、容器的成本高,缺乏狀態儲存等,比較適用於無狀態的計算。

一般來說根據場景需求,通常對不同的架構會組合使用。例如百度監控系統內部是以流式計算與近線計算相結合的方式提供服務的,近線計算從時序資料庫(TSDB)中拉取資料進行計算。對於Trace、線上資料分析等具有比較複雜查詢需求但是相對比較低頻的操作,更適合基於索引查詢的架構。

準確性與時效性

對於實時系統,我們對時效性有更嚴格的需求,但是通常高時效性伴隨著低準確度,二者不可兼得。在分散式環境下,天然存在長尾的延遲資料,這可能是原始資料自身的延遲,也可能是由採集點異常、網路延遲、網路抖動、資料通路中負載等造成的延遲。資料來源越多,分散的越廣,這個長尾效應就會越嚴重,等待資料完整所需要的時間也越長。我們需要在最終資料的準確性和時效性間做折中。

不同場景對兩者的需求不一致,通常來說報警、自動止損等操作需要最高的時效性,能夠容忍一定的精度缺失,在審計、訂單等資料上我們更多的追求準確性,時效性可以適當放寬。解決這個折衷的常用機制是Watermark

Watermark是在資料流中增加標誌資訊,用以指示一個視窗內的資料已經“完全”到達,可以進行計算。

示例:假設我們要統計10s內到達的事件數目,以事件時間(Event Time,即事件攜帶的時間,多為事件產生時間)作為時間基準。如下圖所示,橫線為Wall Time時間線,單位為s。圓球表示事件,圓球裡面的數字為事件時間,其虛線指向產生時間,圓球正對的Wall Time時間線上的點為被計算系統處理的時間(Process Time),兩個時間之間的差值為實際延遲。每個事件都或多或少存在延遲,其中數字為45的圓球延遲最大。對於事件時間[40, 50]這個匯聚視窗,假設我們將Watermark線畫在53處,則我們認為資料在53之前已經完全到達,已經接收到的那些資料可以參與匯聚,Watermark之後到來的事件則忽略。

聊一聊實時計算系統設計

具體怎麼確定Watermark通常取決於需求,對於資料點數量級比較穩定的場景,可以設定一個到達的資料點的比例,在某一個判斷週期內,只要到達的資料點比例滿足閾值則可新增Watermark。主流開源計算框架對Watermark的實際定義不盡相同,具體使用參考對應計算框架的定義。

私以為Watermark機制隱含的一個重要思想是將資料準確性的定義交還給使用者,讓使用者決定。產品或者架構上的功能,存在多種方案的情況下,選擇最泛化的那個方案,暴露出引數然後讓使用者來選擇,不要自己替使用者做決定。當然為了簡化實現成本和使用者使用成本,可以設定固定的一些選項,並選擇一個需求最大的作為預設值。

通常Watermark之後的過期資料點會被丟棄。經常的,除了滿足高時效性需求外,我們也需要在之後保證資料的最終準確性,即在一定時間段之後的資料是準確的。常用思路是部署兩套計算系統,流式計算用以實現低延遲但是準確性低的需求,批次計算用於補償計算資料的準確性,這就是Lambda架構。最典型的使用Lambda架構的場景是從日誌中統計PV/UV,通常是一個流式採集系統和流式計算框架進行實時的PV/UV計算,同時有一套離線系統,定期拉取原始日誌,透過批次計算系統統計準確的PV/UV數值。通常這種架構的缺點是兩套系統的資源消耗,開發運維成本高

聊一聊實時計算系統設計

當前主流計算框架如Spark和Flink對流式和批次計算進行了統一抽象。可以一定程度降低兩套系統的開發運維成本,降低了不同框架的開發運維成本,兩次計算的的資源消耗依舊存在。

對於滿足交換率和結合率的運算元,如常見的統計方法(MAX/MIN/SUM/COUNT),在儲存側支援相同運算的情況下,可以將兩次運算合併成一次。我們內部稱這個方案為多版本,即資料生產一部分就匯聚一部分,每次匯聚產生一個資料版本,由儲存在寫入時合併,或者在查詢時合併。本質上,這是將匯聚的功能遷移了一部分至儲存。

聊一聊實時計算系統設計

百度監控實時計算系統架構

百度監控系統的實時計算系統承擔了監控系統資料處理棧的主要計算功能,每天處理數千億條訊息。本節在實際系統的基礎上,進行了一定的抽象,介紹一個較為通用的系統架構。

聊一聊實時計算系統設計

如圖所示,架構主要包含以下元件:

  • 接入模組:包括資料拉取和資料接收,前者主動拉取資料,後者接收由上游模組推送的資料。

  • 分發模組:根據配置的計算規則,過濾訂閱的資料,並根據排程策略、叢集狀態將規則對應的資料分配到一個或多個處理單元進行計算。

  • 處理單元:包括一個物理計算模組和對應的輸入輸出訊息佇列。物理計算模組執行實際的業務計算邏輯,不同處理單元間可以是同構的也可以是異構的,根據不同的業務場景和使用者需求,可以使用不同的技術棧。

  • 控制模組:接收使用者提交的計算規則和管理操作,分配排程資源,產生對其他模組的控制資訊。

  • 資料推送模組:拉取計算結果,根據計算規則將資料分發到下游模組。

每個物理計算模組都對應一個輸入和輸出訊息佇列,以將資料接入、據輸出與計算層隔離,增加一個新的第三方系統的互動不會影響計算功能。升級變更物理框架不會影響其他元件。

由於大資料處理框架,在其資料規模、節點數目達到一定規模時,其處理效能以及異常恢復速度都會下降。我們將一個固定計算能力以及配套的資源(如訊息佇列)抽象為一個處理單元,每個處理單元處理一部分的資料,取決於計算功能的物理實現,這個處理單元可以對應一個叢集或者一個作業。一個處理單元的具體規模取決於具體的技術選型和硬體條件。確認處理單元的好處是便於容量規劃,可以以一個處理單元作為粒度進行擴縮容。如果需要嫌粒度過大,分層次進行擴縮容,先在一個處理單元內部擴充套件直到極限,之後啟動一個新的處理單元。

實現中需要考慮以下幾個點:

負載均衡

負載均衡發生在系統的每一個層次。

資料接入層與和分發模組之間的採用隨機傳送的策略以均衡分發模組的壓力

資料拉取和資料推送模組需要動態平衡每個例項上的拉取或推送任務,常用的策略是一致性雜湊,以每個任務的實際資料量作為權重。

計算過程是最需要考慮負載均衡的場景,聚合計算通常會遭遇資料傾斜問題,即某些key的資料量遠大於其他,這就造成匯聚該Key的任務OOM。下面提供幾種常用解決思路:

  • 對於滿足交換率和結合率的計算方法,如MAX/MIN/SUM/COUNT等,可以新增多層預聚合,降低最終聚合的資料量。預聚合層次間可以隨機方式,最終匯聚之前按Key雜湊。

聊一聊實時計算系統設計

  • 負載均衡或者說任務排程對應Bin Packing等一系列等價的最最佳化問題。這些問題是NP-Hard的,可以透過近似演算法來逼近,典型的有First Fit演算法。實現時一般需要自定義計算框架的分割槽邏輯,如Spark可以透過自定義Partitioner來實現。

控制節點扇入扇出規模

無論是具備狀態副本的分散式儲存系統、基於DAG的分散式計算系統還是Stateless的接入叢集,當叢集規模持續增大時,節點間互動會顯著增大,最差的情況下全連線,擴容節點會有指數級的連線增長。這會嚴重影響系統對水平擴容能力,擴容帶來的收益跟不上單機資源消耗的增長。

對於分散式系統,透過控制叢集或者作業規模可以實現一定程度的控制,對於接入模組,可以限制下游連線到上限。

聊一聊實時計算系統設計

可用性

對於可用性要求高的服務可以多叢集熱備的方式,在上述架構中,可以透過執行多個並行的處理單元處理相同的資料流來實現。也可以部署整個叢集,透過採集端多寫的方式複製資料流。最後需要根據輸出結果的延遲、準確度等判斷策略選擇一個計算結果輸出。

服務無損升級,可以透過啟動一個新的計算單元,並行處理資料,待資料“預熱”後,進行切換。

在部署時,接入模組儘可能的靠近資料來源,保證每個地域一套。系統多地域部署,每個地域內部模組間儘量自治。接入端傳送資料時優先傳送本地域,異常時嘗試其他地域。模組間互動可以打QoS(服務質量)標籤增加網路優先順序以降低網路丟包。

監控上,除了基礎資源、流量等監控外,最重要的是全通路時延監控,常見方案是構造業務流量,統計在系統中的延遲。這個延遲指標通常是多維度的,根據部署和業務使用情況可能需要關注不同地域,不同業務,不同處理通路的延遲。這些延遲指標,可以指示系統進行流量排程或者資源的重分配。

總  結

本文簡單介紹了百度的分散式監控計算系統架構的演進和當前的實時計算架構,並提供了部分常見問題點解決思路。架構是不斷在演進的,我們的系統僅僅是“夠用”,還有更多的工作需要開展,如架構的輕量化,統一易用的計算表示層,計算的自動最佳化等。

由於個人水平有限,如果行文中有錯誤,或者有需要進一步探討的,請在留言中指出

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31557835/viewspace-2284828/,如需轉載,請註明出處,否則將追究法律責任。

相關文章