摘要:本文整理自阿里雲高階開發工程師 Apache Flink Committer、Flink 1.16 Release Manager 黃興勃(斷塵),在 FFA 2022 核心技術專場的分享。本篇內容主要分為四個部分:
- 綜述
- 持續領先的流處理
- 更穩定易用高效能的批處理
- 蓬勃發展的生態
一、綜述
Flink 1.16 同 Flink 1.15 相比,在 Commits、Issues、Contributors 上,保持了較高的水準。最大的不同是,我們在 Flink 1.16 中大部分的功能和程式碼,主要由中國開發者主導完成。
非常感謝二百四十多位中國 Contributors 對 Flink 1.16 的貢獻。接下來,我們詳細的看一下 Flink 1.16 在三個方面的改進。
二、持續領先的流處理
Flink 作為流式計算引擎的標準,在 Flink 1.16 的流處理方面,依然做了許多的改進和探索。
State 是 Flink 中非常重要的概念。有了 State 的存在,才使得 Flink 在流處理上能夠保證端到端的 Exactly Once 的語義。State 經過多年的持續發展,在 Flink 1.15 提出了 Changelog State Backend,為了解決 RocksDB 由於 TM 需要同時進行 Compaction 和 Upload,導致它的 CPU 和頻寬出現週期性抖動的問題。這部分在引入 Changelog 後得到了解決。
它的基本原理是,當 TM 做 State 操作時,會同時雙寫。一部分資料會像原來一樣,寫到原來的本地 State Table 當中。與此同時,會將 State 資料以 Append Only 的形式,寫到本地 Changelog 中。Changelog 中的這部分資訊,會週期性的上傳到遠端 DFS。
由於這部分 Changelog 資訊相對固定,而且是一種週期定量的形式,所以使得在做 Checkpoint 時,持久化的資料變少,加快了作業 Failover 的速度。其次,因為這份資料相對較少,做 Checkpoint 時的速度會更快。
除此之外,它還改善了 Checkpoint 的問題,解決了 CPU 和頻寬抖動的問題。因為它的速度更快,低延時,使得端到端的資料新鮮度更好,保持在分鐘級別以內。
這部分功能在 Flink 1.16 實現了全面生產可用,整個叢集變得更加穩定。
我們在 Flink 1.16 的 RocksDB 上,也做了很多改進,我們引入了 Rescaling Benchmark。可以觀測 RocksDB 的 Rescaling 耗時,以及耗時的部分在哪裡。
除此之外,我們也在 RocksDB Rescaling 上做了一些改進,大幅提升了 RocksDB Rescaling 的效能。如上圖所示,我們能看到在左圖中,對於一個 WordCount 作業,提升了 3~4 倍的效能。
除了 RocksDB Rescaling 的改進,我們對現有的 State Metrics 和 Monitor 也進行了改進。我們將原來 RocksDB 的一些 log 資訊,重定向到了 Flink log 中。其次,我們將 RocksDB 基於 Database 級別的 Metric 資訊引入到了 Flink 系統中。使用者可以透過 Flink Metric 系統,檢視 RocksDB 的情況。
剛才講了我們在 Flink 1.16 中,對 State 和 RocksDB 的改進。除此之外,我們在 Checkpoint 上也做了很多改進。
在 Flink 1.11 中,我們引入了 Unaligned Checkpoint,並在 Flink 1.13 實現了生產可用。自此,很多公司開始在他們的生產環境中使用 Unaligned Checkpoint。但在使用過程中,也發現了一些問題。某公司的小夥伴在自己的生產環境中,使用了 Unaligned Checkpoint 後,發現了一些問題,並進行了改進,回饋給了社群。
我們簡單看一下 Unaligned Checkpoint 做的一些改進。
第一個是支援透支 buffer。這個功能的引入是為了解決我們 Unaligned Checkpoint 由於 Flink 的執行流程是基於 Mailbox 的處理流程帶來的可能的問題。我們知道,做 Checkpoint 的流程是在主執行緒中進行的,而當主執行緒在處理 Process Function 邏輯時,Process Function 輸出的資料是需要往下游 buffer 輸出需要申請一些 output buffer 的。
在上述過程當中,可能出現在反壓很嚴重的情況時,由於難以申請到 buffer,導致主執行緒卡在了 Process Function 邏輯中。在 Flink 1.16 之前,社群也做了相關的改進:當主執行緒需要進入 Process Function 邏輯前,需要預先申請 output buffer 裡的 buffer。有了這個 buffer 後,它才會進入 Process Function 的邏輯,從而避免卡在裡面。
上述方案解決了部分問題,但是仍沒有解決其他的一類 Case。如果輸入/輸出的資料太大,或者 Process Function 是一個 Flatmap Function,需要輸出多條資料的情況,一個 buffer 將無法滿足,主執行緒依然會卡死在 Process Function 裡。
在 Flink 1.16 中,引入了透支 buffer 的方式。如果 TM 上有額外的一些 buffer 的話,你就可以申請這部分記憶體。然後,透過透支這部分的 buffer,讓主執行緒不會卡死在 Process Function 中,就能正常跳出 Process Function。主執行緒就能接收到 Unaligned Checkpoint Barrier。
之前,Unaligned Checkpoint 引入了一個 Timeout Aligned 機制。如果你的 Input Channel 接收到一個 Checkpoint Barrier 時,在指定時間段內沒有實現 Barrier 對齊的話,Task 將會切換到 Unaligned Checkpoint。但是如果 Barrier 卡在了 output buffer 裡面,下游的 Task 依然是 Aligned Checkpoint。在 Flink 1.16 中,解決了 Barrier 卡在輸出佇列的情況。
透過以上這兩個改進,Unaligned Checkpoint 得到了更大的提升,穩定性也更高。
我們在 Flink 1.16 中,對維表部分的增強。
- 我們引入了一種快取機制,提升了維表的查詢效能。
- 我們引入了一種非同步查詢機制,提升了整個吞吐。
- 我們引入一種重試機制,主要為了解決維表查詢時,遇到的外部系統更新過慢,導致結果不正確,以及穩定性問題。
透過上述改進,我們的維表查詢能力得到了極大提升。
在 Flink 1.16 中,我們支援了更多的 DDL。比如 CREATE FUNCTION USING JAR,支援動態載入使用者的 JAR,方便平臺使用者管理使用者的 UDF。
其次,我們支援 CREATE TABLE AS SELECT,讓使用者便捷的透過已有 Table 建立一個新 Table。
最後,ANALYZE TABLE 是 Table 的一種新語法。幫助使用者生成更高效的統計資訊。這些統計資訊會讓最佳化器產生更好的執行圖,提升整個作業的效能。
除此之外,我們在流上做了很多最佳化。這裡只列舉了幾個比較重要的最佳化。
我們改進了流處理系統中,非確定性問題。這部分非確定性的問題主要包含兩部分,一個是維表查詢上的非確定性問題,另一個是使用者的 UDF 是非確定性的 UDF。
- 我們在 Flink 1.16 提供了一套非常完備的系統性解決方案。首先,我們能夠自動檢測 SQL 中,是否有一些非確定性的問題。其次,引擎幫使用者解決了維表查詢的非確定性問題。最後,提供了一些文件,使用者能根據這些文件,更好的發現和解決自己作業中非確定性的問題。
- 我們終於解決了我們 Protobuf Format 的支援。在 Flink 1.16 中,支援使用者使用 PB 格式資料。
- 我們引入了 RateLimitingStrategy。之前這部分的 Strategy 是定製化,不可配的。在 Flink 1.16 中,我們把它變成可配置。使用者能夠根據自己的網路堵塞策略,實現自己的一套配置。
三、更穩定易用高效能的批處理
剛才我們聊的都是 Flink 在流處理方面的改進。Flink 不僅是一個流式計算引擎,而且是一個流批一體的計算引擎。所以我們在批處理方面,也做了非常多的工作。Flink 1.16 的目標是,使批處理計算夠達到更穩定地應用和高效能。
在易用性方面,現有的批生態中,很多使用者的作業仍執行在 Hive 生態。在 Flink 1.16 中,我們希望 Hive 的 SQL 能夠以非常低價的方式,遷移到 Flink 上。Flink 1.16 的 Hive 生態相容度達到了 94%。如果扣除掉一些 acid 操作,Hive 生態相容度達到了 97%。與此同時,配合 Catalog,Hive SQL 在 Flink 引擎上,能夠執行聯邦查詢的能力。
在 Flink 1.16 中,我們還引入了一個非常重要的元件 SQL Gateway。透過 SQL Gateway,以及支援的 HiveServer2,使得 Hive 生態中主流的生態產品可以非常自然的接入 Flink 生態。
在 Flink 1.16 SQL Gateway 中,我們支援多租戶,相容 HiveServer2 協議,以及 HiveServer2 帶來的 Hive 生態。有了 HiveServer2 的配合,整個 Hive 生態就能非常便捷的遷移到 Flink 生態上。
接下來,看看 Flink 引擎本身為批做了哪些最佳化。首先,講一講與排程相關的最佳化。Flink 批作業經常會遇到這樣的問題。由於一些熱點機器的 IO 繁忙或 CPU 高負載,導致機器上執行的任務拖累 Flink 批作業端到端的執行時間。
在 Flink 1.16 中,為了解決這個問題,我們引入了 Speculative Execution,一種推測執行的方式。它的基本原理是,在每個階段,如果我們檢測到某一個機器,它是一種熱點機器,它上面執行的任務被稱為慢任務。所謂慢任務就是,它的慢任務執行時間比同一階段其他任務的執行時間要長的多,從而把這臺機器定義為熱點機器。
有了熱點機器之後,為了降低整個作業的執行時間。我們希望把熱點機器上執行的慢任務,透過一個備份任務,讓它能夠執行在其他非熱點機器上。從而使得整個任務的總執行時間縮短。
接下來,我們簡單看一下它的具體細節。首先,有一個叫 Slow Task Detector 的元件。這個元件會週期性的檢視是否有一些慢任務以及慢任務對應的熱點機器。
收集到了這些資訊後,它會彙報給 Speculative Scheduler。Scheduler 會把這些資訊彙報給 Blocklist Handler。然後 Blocklist Handler 會把這些機器加黑。
有了這些加黑機器之後,加黑機器上慢任務的備份任務會被排程到叢集當中其他非熱點的機器之上,讓這些慢任務和備份任務同時執行。誰先完成就承認哪個任務的結果。被承認的那個例項,它的輸出也能作為下游運算元的輸入。沒能完成的任務將會被 cancel 掉。
在 Speculative Execution 中,我們也引入了一些 Rest 和 Web UI 的支援。如上左圖所示,可以觀察到哪些慢任務被取消,哪些是其備份任務。透過右圖,可以實時看到哪些 TM 機器被標成了 black 機器。
關於 Speculative Execution 的後續工作,我們當前不支援在 Sink 上的 Speculative Execution。其次,我們現有的檢測策略比較粗糙。我們並沒有有效的考慮到,由於資料傾斜導致一些慢任務的檢測錯誤。把一些本身是正常的機器,標成了熱點機器。這都是我們在 Flink 1.17 之後,需要做的工作。
我們在 Shuffle 上做的工作。眾所周知,Flink 有兩個 Shuffle 策略,一個是 Pipelined Shuffle,另一個是 Blocking Shuffle。
流式 Pipelined Shuffle 的上下游 Task,能夠同時排程執行。它的資料傳輸是一種空對空的傳輸,資料不落盤,效能更好。但它的缺點是,會佔用更多的資源。因為它需要上下游的 Task,同時排程。在一些資源比較緊張的情況下,可能導致作業難以拉起,或者整個作業因為資源索取,造成死鎖。
在 Blocking Shuffle 方面,由於它在每個階段,Task 都會把它的結果寫到磁碟裡。然後,下游的 Task 再透過磁碟,讀取它的資料。這樣是好處是,理論上只需要一個 Slot,就能完成整個批作業的執行。但它的缺點也顯而易見。因為每個階段都要把結果資料落盤,下一步還需要讀磁碟,所以它的效能較差。
基於這種考慮,我們在 Flink 1.16 提出了一種新的 Shuffle 策略,即 Hybrid Shuffle。其目是同時利用上述兩套 Shuffle 的優點。在資源充足時,我們利用 Pipelined Shuffle 的效能優勢。在資源不足時,我們利用 Blocking Shuffle 的資源優勢。整套 Shuffle 策略是自適應切換的,這是 Hybrid Shuffle 的基本思想。
Hybrid Shuffle 在資料落盤方面,有兩套策略。一套是全落盤,另一套是選擇性落盤。
選擇性落盤的好處是,我們寫更少的資料落盤,整個效能相對更高。而全落盤的好處是在 Failover 時的效能會更好。根據使用者場景是哪種不同,選擇到底用 Hybrid Shuffle 的哪種落盤策略。
在效能方面,Flink 1.16 的 Hybrid Shuffle 相比 Blocking Shufle,TPC-DS 執行時間減少了 7.2%。如果加上廣播方面的最佳化,最佳化後的 TPC-DS 執行時間比會比 Blocking Shuffle 減少 17%。
關於 Hybrid Shuffle 的後續工作,一個是廣播方面的效能最佳化。另一個是,與 Flink 1.15 提出的 Adaptive Batch Scheduler 適配,以及 Speculative Execution 的適配。
如上圖所示,我們在批處理方面還有許多其他最佳化。我們簡單列了一些比較重要的最佳化。
- 首先,我們支援了 Dynamic Partition Pruning,即動態分支裁剪。在 1.16 以前的分支裁剪策略都是基於執行圖上的靜態裁剪。但在批處理上,完全可以利用 Runtime 的一些統計資訊,更加高效的進行分支裁剪策略。這套實現讓 Flink 1.16 在 TPC-DS 上有 30%的效能提升。
- 我們引入了 Adaptive Hash Join,一種自適應策略。我們利用 Runtime 的一些統計資訊,自適應的將 Hash Join 回退到 Sort Merge Join,提升 Join 的穩定性。
- 我們在批處理之前的 Blocking Shuffle 上做了一些改進。我們引入了更多的壓縮演算法(LZO 和 ZSTD)。新的壓縮演算法是為了解決在資料大小以及 CPU 消耗上的平衡。
- 我們最佳化了現有的 Blocking Shuffle 的實現。透過自適應的 buffer 分配,IO 順序讀取,以及 Result Partition 共享,在 TPC-DS 上有 7%的效能提升。
我們在 Batch SQL 上,支援 Join Hints。Join Hints 讓使用者能手動干預 Join 策略。使用者將會知道生成更加高效的執行計劃,提升整個作業的效能。
四、蓬勃發展的生態
接下來,介紹一些蓬勃發展的生態產品。如上圖所示,PyFlink 是我們生態中非常重要的產品。PyFlink 經過 Flink 1.9 的一路發展到了 Flink 1.16。
- Python API 的覆蓋度達到了 95%以上。一方面,我們最佳化內建 Window 的支援。在 Flink 1.16 以前,我們在 Flink 1.15 支援了自定義 Window。但對於需要自定義的 Window,使用者的實現成本依然較高,難以使用。另一方面,我們在 Flink 1.16 引入了 side output、broadcast state 等支援。
- PyFlink 支援支援所有的內建 Connector&Format。擴充了 PyFlink 對接各種系統的能力。
- PyFlink 支援 M1 和 Python 3.9。有了這兩部分能力,降低了使用者的上手成本。與此同時,Deprecate Python 3.6,將在 Flink 1.17 裡移除對 Python3.6 的支援,引入 Python3.10 的支援。
- PyFlink 搭建了自己的使用者網站。提供了各種執行環境下的安裝教程,可以線上執行 QuickStart 例子。這些例子直接掛載在線上的 notebook 網站。與此同時,我們總結了許多使用者常見的問題答疑,方便新使用者上手。同時我們整理了 PyFlink 端到端的場景案例。這些部分內容本質上是為了降低新使用者的門檻。
在效能方面,我們在 PyFlink 1.15 時,引入了 Thread Mode。Thread Mode 相對於 Process Mode 最大的不同是,它解決了 Python 程式和 Java 程式間的通訊問題。如果是程式間通訊,將會有一些序列化/反序列化的開銷,而 Thread Mode 將不再有這種問題。
在 Flink 1.16,我們對 Thread Mode 進行了完整的支援。相對於 Process Mode,它的效能會更好,端到端的延遲會更低。
如上圖所示,在 JSON 計算的場景下,Thread Mode 的端到端延遲只有 Process Mode 的 1/500。它的效能在通用的典型場景,以及資料比較常見的場景之下,Thread Mode 的效能基本追平了 Java。
由此可見,在 Flink 1.16 中,PyFlink 在功能和效能上,已經達到全面生產可用。除此之外,CEP 也是 Flink 生態中很重要的一部分。我們在 Flink 1.16,對 CEP 的功能進行擴充。
- 我們在 Batch SQL 上,支援了 CEP 能力。
- 我們擴充了原有隻支援首尾時間間隔的功能,支援了定義事件、事件間隔。
剛才講的是 Flink 內部重要的生態產品,在 Flink 專案外,我們還有一些重要的生態專案。比如 Flink Table Store、Flink CDC、Flink ML、Feathub。
- Flink Table Store 配合 Changelog State Backend,實現端到端資料的新鮮度達到分鐘級別內。
- 我們在資料的正確性問題上,做了一些改進。使得 CDC 流進來後做 Join 和聚合會更加流暢。
- 我們在 DataStream 上支援了 Cache 功能,使 Flink ML 在實現內建運算元時,能夠得到更高效能。
- 前一段剛剛開源的 Feathub 專案。Feathub 依賴 PyFlink 作為它的計算引擎底座。隨著 PyFlink 效能的提升,Feathub 使用 Python Function 的效能接近 Java Function 的效能,不再有劣勢。
更多內容
<p style="text-align:center"><img src="https://img.alicdn.com/imgextra/i3/O1CN0102Wuzs1dUVfQKlv59_!!6000000003739-2-tps-1920-675.png" alt="img" style="zoom:100%;" /></p>
活動推薦
阿里雲基於 Apache Flink 構建的企業級產品-實時計算Flink版現開啟活動:
99 元試用 實時計算Flink版(包年包月、10CU)即有機會獲得 Flink 獨家定製衛衣;另包 3 個月及以上還有 85 折優惠!
瞭解活動詳情:https://www.aliyun.com/product/bigdata/sc