Apache Flink 1.9.0做了這些修改

阿里妹導讀:8月22日,Apache Flink 1.9.0 正式發佈。早在今年1月,阿里便宣佈將內部過去幾年打磨的大數據處理引擎Blink進行開源並向 Apache Flink 貢獻代碼。此次版本在結構上有重大變更,修改代碼達150萬行,接下來,我們一起梳理 Flink 1.9.0 中非常值得關注的重要功能與特性。

Flink 1.9.0是阿里內部版本 Blink 合併入 Flink 後的首次發版,修改代碼150萬行,此次發版不僅在結構上有重大變更,在功能特性上也更加強大與完善。本文將爲大家介紹 Flink 1.9.0 有哪些重大變更與新增功能特性。

在此先簡單回顧一下阿里巴巴Blink 開源的部分要點:

  • Blink 開源的內容主要是阿里巴巴基於開源 Flink 引擎,依託集團內部業務,在流計算和批處理上積累的大量新功能、性能優化、穩定性提升等核心代碼。
  • Blink 以分支的形式開源,即開源後會成爲 Apache Flink項目下的一個分支。
  • Blink 開源的目標不是希望成爲另一個活躍的項目,而是將Flink 做的更好。通過開源的方式讓大家瞭解所有 Blink 的實現細節,提高 Blink 功能merge進入Flink 的效率,與社區協作更高效。

半年的時間過去了,隨着 Flink 1.9.0 版本的發佈,在此我們可以驕傲的宣佈:Blink 團隊已經實現了之前的諾言!儘管不是所有功能都順利 merge 回了社區,但是在我們和社區的共同努力下,Flink 正在朝着它最初的夢想大踏步的邁進。

先和大家分享幾個 Flink 1.9.0 版本與之前個版本的對比數字:

  • 從解決的 issue 數量和代碼 commit 數量來看,1.9.0 已經達到甚至超過了之前兩個版本的總和。
  • 從修改的代碼行數來看,達到了驚人的150 萬行。雖然受一些模塊重構以及 Blink merge 等因素的影響,但不可否認的是,1.9.0 版本一定是 Flink 有史以來開發者們最活躍的版本。
  • 從Contributor 數量來看,Flink 也已經吸引了越來越多的貢獻者。我相信其中就有不少來自中國的用戶和開發者,社區也響應號召開通了中文郵件列表。

那麼,1.9.0 版本究竟由哪些變更而引發瞭如此大量的修改,以下將詳細說明。

發佈地址

Apache Flink 1.9.0 已經正式發佈,地址:https://flink.apache.org/news/2019/08/22/release-1.9.0.html

架構升級

基本上,系統如果有非常大的變動,那一定是架構升級帶來的。這次也不例外,Flink 在流批融合的方向上邁進了一大步。首先我們來看一下 Flink之前版本的架構圖:

相信熟悉Flink 的讀者們對左邊的架構圖一定不會感到陌生。簡單來說,Flink 在其分佈式流式執行引擎之上,有兩套相對獨立的 DataStream 和 DataSet API,分別來描述流計算和批處理的作業。在這兩個 API之上,則提供了一個流批統一的API,即 Table API 和SQL。用戶可以使用相同的Table API 程序或者 SQL 來描述流批作業,只是在運行時需要告訴 Flink 引擎希望以流的形式運行還是以批的流式運行,此時 Table 層的優化器就會將程序優化成 DataStream 作業或者 DataSet 作業。

但是如果我們仔細查看 DataStream 和 DataSet 底層的實現細節,會發現這兩個 API 共享的東西其實不多。它們有各自獨立的翻譯和優化的流程,而且在真正運行的時候,兩者也使用了完全不同的 Task。這樣的不一致對用戶和開發者來講可能存在問題。

從用戶的角度來說,他們在編寫作業的時候需要在兩個 API 之間進行選擇,而這兩個 API 不僅語義不同,同時支持的 connector 種類也不同,難免會造成一些困擾。Table 儘管在 API 上已經進行了統一,但因爲底層實現還是基於 DataStream 和 DataSet,也會受到剛纔不一致的問題的影響。

從開發者角度來說,由於這兩套流程相對獨立,因此基本上很難做到代碼的複用。我們在開發一些新功能的時候,往往需要將類似的功能開發兩次,並且每種 API 的開發路徑都比較長,基本都屬於端到端的修改,這大大降低了我們的開發效率。如果兩條獨立的技術棧長期存在,不僅會造成人力的長期浪費,最終可能還會導致整個 Flink 的功能開發變慢。

在 Blink 一些先行探索的基礎之上,我們和社區的開發人員進行了密切的討論,最終基本敲定了 Flink 未來的技術架構路線。

在 Flink 的未來版本中,我們將捨棄 DataSet API,用戶的 API 主要會分爲偏描述物理執行計劃的 DataStream API 以及偏描述關係型計劃的 Table & SQL。DataStream API 提供給用戶更多的是一種“所見即所得”的體驗,由用戶自行描述和編排算子的關係,引擎不會做過多的干涉和優化。而Table API & SQL 則繼續保持現在的風格,提供關係表達式API,引擎會根據用戶的意圖來進行優化,並選擇最優的執行計劃。值得一提的是,以後這兩個 API 都會各自同時提供流計算和批處理的功能。這兩個用戶 API 之下,在實現層它們都會共享相同的技術棧,比如會用統一的 DAG 數據結構來描述作業,使用統一的 StreamOperator 來編寫算子邏輯,包括使用統一的流式分佈式執行引擎。

TableAPI & SQL

在開源 Blink 時,Blink 的Table 模塊已經使用了 Flink 未來設想的新架構。因此 Flink 1.9 版本中,Table 模塊順理成章的成爲了架構調整後第一個喫螃蟹的人。但是,爲了儘量不影響之前版本用戶的體驗,我們還是需要找到一個方式讓兩種架構能夠並存。

基於這個目的,社區的開發人員做了一系列的努力,包括將 Table 模塊進行拆分(FLIP-32,FLIP 即 Flink Improvement Proposals,專門記錄一些對Flink 做較大修改的提議),對 Java 和 Scala 的 API 進行依賴梳理,並且提出了 Planner 接口以支持多種不同的 Planner 實現。Planner 將負責具體的優化和將 Table 作業翻譯成執行圖的工作,我們可以將原來的實現全部挪至 Flink Planner 中,然後把對接新架構的代碼放在 Blink Planner裏。

圖中的 Query Processor 就是 Planner 的實現

這樣的做法一舉兩得。不僅讓 Table 模塊在經過拆分後更加清晰,更重要的是不影響老版本用戶的體驗。

在 1.9 版本中,我們已經merge 了大部分當初從 Blink 開源出來的 SQL功能。這些都是近幾年在阿里內部場景經過千錘百煉而沉澱出來的新功能和性能上的優化,相信能夠促使Flink 更上一個臺階!

除了架構升級之外,Table 模塊在 1.9 版本還做了幾個相對比較大的重構和新功能,包括:

  • FLIP-37:重構 Table API 類型系統
  • FLIP-29:Table 增加面向多行多列操作的 API
  • FLINK-10232:初步的 SQL DDL 支持
  • FLIP-30:全新的統一的 Catalog API
  • FLIP-38:Table API 增加 Python 版本

有了這些新功能加持,再經過後續修復和完善,Flink Table API 和 SQL 在未來將會發揮越來越重要的作用。

批處理改進

Flink的批處理功能在 1.9 版本有了重大進步,在架構調整後,Flink 1.9 加入了好幾項對批處理的功能改進。

首當其衝的是優化批處理的錯誤恢復代價:FLIP-1(Fine Grained Recovery from Task Failures),從這個 FLIP 的編號就可以看出,該優化其實很早就已經提出,1.9 版本終於有機會將 FLIP-1 中未完成的功能進行了收尾。在新版本中,如果批處理作業有錯誤發生,那麼 Flink 首先會去計算這個錯誤的影響範圍,即 Failover Region。因爲在批處理作業中,有些節點之間可以通過網絡進行Pipeline 的數據傳輸,但其他一些節點可以通過 Blocking 的方式先把輸出數據存下來,然後下游再去讀取存儲的數據的方式進行數據傳輸。如果算子輸出的數據已經完整的進行了保存,那麼就沒有必要把這個算子拉起重跑,這樣一來就可以把錯誤恢復控制在一個相對較小的範圍裏。

如果作業極端一點,在每一個需要Shuffle 的地方都進行數據落盤,那麼就和 MapReduce 以及 Spark 的行爲類似了。只是 Flink 支持更高級的用法,你可以自行控制每種 Shuffle 是使用網絡來直連,還是通過文件落盤來進行。

有了基於文件的Shuffle 之後,大家很容易就會聯想到,是不是可以把這個 Shuffle 的實現變成插件化。沒錯,社區也正在朝這個方向進行改進:FLIP-31(Pluggable Shuffle Service)。比如,我們可以利用 Yarn 的 Auxliary Service 來作爲一種 Shuffle 的實現,我們甚至可以去寫一個分佈式服務來幫助批處理任務進行Shuffle。最近,Facebook 也分享了一些這方面的工作,而且在阿里內部,我們已經使用這樣的架構,支持了單作業處理數百TB 量級的規模。Flink 具備了這樣的插件機制後,可以輕鬆的對接這些更加高效靈活的實現,讓Shuffle 這個批處理的老大難問題得到較好的解決。

流處理改進

流計算畢竟還是 Flink 發跡的主要領域,在 1.9 版本當然也不能忘了在這方面做一些改進。這個版本增加了一個非常實用的功能,即FLIP-43(State Processor API)。Flink 的 State 數據的訪問,以及由 State 數據組成的 Savepoint 的訪問一直是社區用戶呼聲比較高的一個功能。在 1.9 之前的版本,Flink 開發了 Queryable State,不過這個功能的使用場景比較有限,使用效果也不太理想,因此用的人一直不多。這次的 State Processor API 則提供了更加靈活的訪問手段,也能夠讓用戶完成一些比較黑科技的功能:

  1. 用戶可以使用這個 API 事先從其他外部系統讀取數據,把它們轉存爲 Flink Savepoint 的格式,然後讓 Flink 作業從這個 Savepoint 啓動。這樣一來,就能避免很多冷啓動的問題。
  2. 使用 Flink 的批處理 API 直接分析State 的數據。State 數據一直以來對用戶是個黑盒,這裏面存儲的數據是對是錯,是否有異常,用戶都無從而知。有了這個 API 之後,用戶就可以像分析其他數據一樣,來對 State 數據進行分析。
  3. 髒數據訂正。假如有一條髒數據污染了你的 State,用戶還可以使用這個 API 對這樣的問題進行修復和訂正。
  4. 狀態遷移。當用戶修改了作業邏輯,想複用大部分原來作業的 State,但又希望做一些微調。那麼就可以使用這個 API 來完成相應的工作。

上面列舉的都是流計算領域非常常見的需求和問題,都有機會通過這個靈活的 API 進行解決,因此我個人非常看好這個 API 的應用前景。

說到 Savepoint,這裏也提一下社區完成的另外一個實用功能,即FLIP-34(Stop with Savepoint)。大家都知道 Flink 會週期性的進行 Checkpoint,並且維護了一個全局的狀態快照。假如我們碰到這種場景:用戶在兩個Checkpoint 週期中間主動暫停了作業,然後過一會又進行重啓。這樣,Flink 會自動讀取上一次成功保存的全局狀態快照,並開始計算上一次全局快照之後的數據。雖然這麼做能保證狀態數據的不多不少,但是輸出到 Sink 的卻已經有重複數據了。有了這個功能之後,Flink 會在暫停作業的同時做一次全局快照,並存儲到Savepoint。下次啓動時,會從這個 Savepoint 啓動作業,這樣 Sink 就不會收到預期外的重複數據了。不過,這個做法並不能解決作業在運行過程中自動Failover而引起的輸出到 Sink 數據重複問題。

Hive集成

Hive一直是 Hadoop 生態中一股不可忽視的重要力量。爲了更好的推廣 Flink 的批處理功能,和 Hive 的集成必不可少。在 1.9 版本的開發過程中,我們也很開心迎來了兩位 Apache Hive PMC 來推進 Flink 和 Hive 的集成工作。

首先要解決的是使用 Flink 讀取 Hive 數據的問題。通過 FLIP-30 提出的統一的 Catalog API 的幫助,目前 Flink 已經完整打通了對 Hive Meta Store 的訪問。同時,我們也增加了 Hive 的 Connector,目前已支持 CSV, Sequence File, Orc, Parquet 等格式。用戶只需要配置 HMS 的訪問方式,就可以使用 Flink 直接讀取 Hive 的表進行操作。在此基礎之上,Flink 還增加了對 Hive 自定義函數的兼容,像 UDF, UDTF和 UDAF,都可以直接運行在Flink SQL裏。

在寫的支持上,目前Flink 還支持的比較簡單,暫時只能 INSERT INTO 一張新表。不過和 Hive 的兼容一直是社區工作中一個高優先級的事情,相信後續的版本會有持續的改善。

總結

Flink1.9.0 版本經過大半年的緊張開發,終於順利發佈。在這過程中,Flink 社區不僅迎來了相當多的中國開發者和用戶,還迎來了海量的代碼貢獻,預示着一個良好的開端。未來,無論是功能還是生態,我們會繼續在 Flink 社區加大投入,讓 Flink 在整個中國乃至全世界大規模的使用起來。我們也衷心希望有更多的開發者可以加入我們,加入Flink 社區,一起把 Apache Flink 做的越來越好!

 

原文鏈接:https://zhuanlan.zhihu.com/p/79434753

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