摘要:本文整理自阿里雲高階技術專家朱翥,在 FFA 核心技術專場的分享。本篇內容是關於在過去的一年中,Apache Flink 對執行時的作業執行管控進行的一些改進。
這些改進,讓 Flink 可以更好的利用執行時的資訊,來靈活的控制作業的執行,從而使得 Flink 批處理作業的執行可以更加的穩定、更有效率,並且更容易運維。
詳細內容主要分為兩個部分:
- 自適應執行計劃
- 同源例項的並行執行
一、自適應執行計劃
我們先看一下,Flink 是如何描述作業的執行計劃的。以這個 DataStream 作業為例,Flink 會基於它先生成一個 StreamGraph。這是一個有向無環圖,圖中的節點對應著計算邏輯,圖中的邊則對應著資料的分發方式。
Flink 會根據節點的並行度以及他們之間的連邊方式,把一些計算節點進行連結合併,最終形成 JobGraph,從而降低計算節點間的資料傳輸開銷。這個操作的目的是,是為了降低計算節點之間的資料傳輸開銷。StreamGraph 和 JobGraph 都是在編譯階段生成的。JobGraph 會提交給 Flink Job Manager,從而啟動和執行作業。
在執行作業前,Flink 會生成 ExecutionGraph。這個 ExecutionGraph 是根據 JobGraph 中的節點並行度,展開生成的。 我們知道,Flink 是一個分散式計算框架。而 ExecutionGraph 的每一個節點,都對應著一個需要部署到 TaskManager 上進行執行的任務,每一條邊都對應著任務的輸入和輸出。所以說,它是作業的物理執行計劃。
這個物理執行計劃,描述了任務的計算邏輯、所需資源和並行度,同時也描述任務產出資料的劃分方式,此外還描述了任務對資料的依賴關係以及資料傳輸方式。
透過它,Flink 就能知道如何建立和排程作業的所有任務,從而完成作業的執行。
但是,如前面所說,它是在作業執行前就已經確定的,是靜態的。而 Flink 難以在作業執行前,預判什麼樣的計劃引數更合理。所以,這些執行計劃引數,只能依賴使用者提前指定,也就是需要手動調優。
然而,對於批作業,由於其分階段執行的特性,在執行一個階段前,理論上 Flink 是可以獲得很多有用的資訊的,比如其消費的資料量大小、這些資料的分佈模式、當前的可用資源等等。
基於這些資訊,我們可以讓 Flink 對執行計劃動態的進行調優,從而獲得更好的執行效率。並且,由於 Flink 可以自動的進行這些調優,也可以讓使用者從手動調優中解放出來。
這就是 Flink 批處理作業的自適應執行計劃。
為了支援自適應執行計劃,最核心的一點,是需要一個可以動態調整的執行拓撲。所以,我們改造了 ExecutionGraph,使其支援漸進式構建。
具體的來說,就是讓 ExecutionGraph 一開始只包含 Source 節點,隨著執行的推進,再逐漸的加入後續的節點和連邊。
這樣,Flink 就有機會對尚未加入的執行節點和連邊進行調整。
但在這個地方,我們遭遇了一個阻礙。因為在原來的作業執行中,上游節點執行是依賴於下游節點的並行度的。具體來說,是因為上游在產出資料時,會根據下游並行度,對資料進行劃分(sub-partition);這樣,每個下游任務就可以直接消費其對應的那一個資料分割槽。然而,在動態執行計劃的場景下,下游節點的並行度是不確定的。
為了解決這個問題,我們改造了節點資料的劃分邏輯,使其不再根據下游節點的並行度,而是根據其最大並行度進行劃分。同時,我們也改造了節點消費資料的邏輯,使其不再只消費單一分割槽,而是可以消費一組連續的資料分割槽(sub-partition range)。
透過這樣的方式,上游節點執行得以和下游節點的並行度解耦,動態執行拓撲也得以實現。
在支援了動態執行拓撲後,我們引入了 Adaptive Batch Scheduler 來支援自適應執行計劃。
與原有排程器不同的地方在於,Adaptive Batch Scheduler 會基於動態執行拓撲進行作業管控,持續收集執行時的資訊,定製後續的執行計劃。Flink 會基於執行計劃,動態生成執行節點和連邊,以此來更新執行拓撲。
在上述框架下,我們為 Flink 增加了自動決定並行度的能力。使用者只需要配置希望單個執行節點處理的資料量, Flink 就可以根據該階段需要處理的資料量,自動推導該階段的節點並行度。
相比起傳統的為每個作業單獨配置並行度,自動決定並行度有這些優點:一是配置簡單,無需為每個作業單獨配置,一項配置可以適用於很多作業;二是可以自動的適配每天變化的資料量,當資料量較大時,作業並行度可以大一些,從而保障作業的產出時間;三是可以細粒度的調整作業的並行度,提高資源利用率。
但是自動決定並行度,資料可能分佈不均。為了解決這個問題,我們在自動決定並行度的基礎上,進行了自動均衡下發資料的改進。
這個改進會採集 sub-partition 粒度的資料量,並以此來決定執行節點的並行度,以及每個執行節點應該消費哪些分割槽資料。從而儘可能讓下游各執行節點消費的資料,接近使用者配置的預期值。
相比起自動決定並行度,這樣的方式不但讓下游資料量更均衡,而且能夠緩解資料傾斜的影響。這個功能正在開發中,會隨著 Flink 1.17 釋出。
以上就是我們當前已經或是即將在 Flink 中完成的自適應執行計劃的改進。
不過,自適應執行計劃還有更大的改進空間,比如根據 join 運算元實際消費的資料量,動態決定應該用 hash join 還是 broadcast join;支援選擇性執行任務,在滿足特定條件下,為作業加入額外的執行分支;在 Sink 輸出結果達標時提前結束作業。
此外,我們也在考慮 SQL 的動態最佳化能力。
當前,SQL 的查詢最佳化是在作業編譯時進行的;其只能透過 Source 的 Meta 資訊,對資料量進行估算,容易導致最佳化結果不準確。如果可以向 SQL planner 反饋執行時資訊,來動態的最佳化執行計劃,就可以得到更好的執行效果。
二、同源例項的並行執行
接下來,講一講同源例項的並行執行。
同源例項是指,屬於同一個執行節點的執行例項。執行拓撲是由執行節點組成,各節點會建立執行例項,將其部署到 TaskManager 上進行執行。
當前,每個執行節點在某一時刻只能有一個執行例項,只有當該例項失敗(或被取消)後,節點才會建立一個新的執行例項。這也意味著,同源執行例項只能序列執行。
驅動我們更改這一現狀的,是來自預測執行的需求。
在生產中,熱點機器是無法避免的,混部叢集、密集回刷,都可能導致一臺機器的負載高、IO 繁忙。其上執行的資料處理任務可能異常緩慢,導致批作業產出時間難以得到保障。
預測執行,是一種已經得到普遍的認可、用來解決這類問題的方法。
其基本思路是,為熱點機器上的慢任務建立新的執行例項,並部署在正常的機器節點上。這些預測執行例項和對應的原始例項,具有相同的輸入和產出。其中,最先完成的例項會被承認,其他相應例項會被取消。
因此,為了支援預測執行,Flink 必須支援多個同源例項並行執行。為了支援同源例項並行執行,我們進行了下列改進。
首先,我們重新梳理了執行節點的狀態。
當前,執行節點的狀態和其當前唯一執行例項是一一對應的。然而,如果一個節點可以同時存在多個執行例項,這樣的對映方式就會出現問題。
為此,我們重新定義了執行節點與執行例項的狀態對映,取執行例項中最接近 FINISH 狀態的狀態作為執行節點的狀態。這樣既可以相容單執行例項場景,也能支援多個同源例項並行執行的場景。
其次,我們保證了 Source 的同源執行例項,總是會讀取到相同的資料。
大體上來說,就是我們在框架層為每個 Source 執行節點增加一個列表,來維護分配給它的資料分片。該節點的所有執行例項都會共享這一個列表,只是會各自維護一個不同的下標,來記錄其處理到的資料分片進度。
這樣的改動的好處是,大部分現有 Source 不需要額外的修改,就可以進行預測執行。只有當 Source 使用了自定義事件的情況下,它們才需要實現一個額外的介面,用以保證各個事件可以被分發給正確的執行例項。
在接下來的 Flink 1.17 中,我們也會支援 Sink 的同源執行例項並行執行。
其關鍵點在於避免不同 Sink 之間的執行衝突,特別是要避免因此產生的資料不一致,因為 Sink 是需要向外部系統進行寫入的。
由於 Sink 的寫入邏輯隱藏在各個 Sink 的實現中,我們無法像 Source 一樣在框架層統一避免寫入衝突。所以我們向 Sink 層暴露了執行例項標識(attemptNumber),使 Sink 可以自行避免衝突。
同時為了安全起見,我們預設不會允許 Sink 的同源執行例項並行執行,除非 Sink 顯式宣告支援同源執行例項並行執行。
在此基礎上,我們為 Flink引入了預測執行機制。主要包括三個核心元件。
首先是慢任務檢測器。它會定期進行檢測,綜合任務處理的資料量,以及其執行時長,評判任務是否是慢任務。當發現慢任務時,它會通知給批處理排程器。
其次是批處理排程器。在收到慢任務通知時,它會通知黑名單處理器,對慢任務所在的機器進行加黑。並且,只要慢任務同源執行的例項數量,沒有超過使用者配置上限,它會為其拉起並部署新的執行例項。當任意執行例項成功完成時,排程器會取消掉其他的同源執行例項。
最後是黑名單處理器。Flink 可以利用其加黑機器。當機器節點被加黑後,後續的任務不會被部署到該機器。為了支援預測執行,我們支援了軟加黑的方式,即加黑機器上已經存在的任務,可以繼續執行而不會因為加黑被取消掉。
除此之外,工作人員對外部 UI 進行改進,方便展示當前執行中的所有同源執行例項,使用者可以更好的判斷預測執行的執行結果。
此外,我們對 WebUI 也進行了改進,使其能夠展示當前執行中,或是作業結束時的所有同源執行例項,使用者可以更好的判斷預測執行的執行結果。此外,UI 也能展示被加黑的 Slot 和 TaskManager。
需要說明的是,雖然出發點是支援批作業的預測執行。同源執行例項的並行執行,也為流作業的任務平滑遷移提供了可能。
當流作業有任務落在慢機器上時,我們也可能先為其預先拉起一個同源執行例項,待該例項的部署和初始化完成後,透過直接切換資料連邊,可以達成低斷流的任務遷移。配合慢任務檢測、黑名單等能力,我們甚至能讓 Flink 自動的進行慢任務遷移。
更多內容
活動推薦
阿里雲基於 Apache Flink 構建的企業級產品-實時計算Flink版現開啟活動:
99 元試用 實時計算Flink版(包年包月、10CU)即有機會獲得 Flink 獨家定製衛衣;另包 3 個月及以上還有 85 折優惠!
瞭解活動詳情:https://www.aliyun.com/produc...