Flink整合面向使用者的資料流SDKs/API(Flink關於棄用Dataset API的論述)

2022-06-02 18:01:13

動機

Flink提供了三種主要的sdk/API來編寫程式:Table API/SQL、DataStream API和DataSet API。我們認為這個API太多了,建議棄用DataSet API,而使用Table API/SQL和DataStream API。當然,這說起來容易做起來難,所以在下面,我們將概述為什麼我們認為太多的api對專案和社群有害。然後,我們將描述如何增強Table API/SQL和DataStream API以包含DataSet API的功能。
在本FLIP中,我們將不描述如何增強Table API/SQL和DataStream的所有技術細節。目標是在棄用DataSet API的想法上達成共識。必須有後續的flip來描述我們所維護的api的必要更改。

為什麼Flink有三個api?

這三種api在專案的生命週期中被有機地開發出來,最初是為特定的用例設計的。DataSet API是Flink最古老的API,支援有界資料的批次處理執行。有些人可能不記得了,但Flink最初是一個批次程式。在早期,社群意識到其基於管道的體系結構非常適合流處理,這就產生了DataStream API。後者是為無界的流用例開發的,具有處理狀態、事件時間和視窗的特殊設施。隨著Flink在分析領域的流行,Table API/SQL被引入,以提供支援批次處理和流處理的高階關係API。
對於下面的討論,理解每個API的區別特性將會很有幫助。

DataSet API:

  • 只支援有界源
  • 沒有為事件時間/視窗提供特殊支援
  • 全有或全無輸出:作業要麼產生資料,要麼不產生資料
  • 用於大規模批次處理作業的細粒度的、基於區域的故障轉移。執行中某一部分的失敗並不一定需要重新啟動整個拓撲
  • 高效的資料庫式操作符:雜湊連線、合併連線、對使用輸入資料有界知識的聚合進行排序/分組

DataStream資料API:

  • 源可以是有界的,也可以是無界的
  • 對事件時間和視窗的特殊支援
  • 基於水印或檢查點的「增量」輸出
  • 故障恢復檢查點,這意味著在一個運算元失敗的情況下重新啟動整個拓撲
  • 你可以執行有界程式,但效率不高:
    • 悲觀的假設,沒有結束標識,「你不知道接下來會發生什麼」
    • 對於聚合,需要將所有鍵儲存在一個「雜湊對映」中
    • 對於事件時間處理,我們需要保持多個「視窗」開啟
    • 沒有基於阻塞、持久洗牌的細粒度恢復

Table/SQL API:

  • 有界和無界源
  • 一個宣告性API,以及SQL
  • 資料有一個預先知道的結構,因此允許額外的優化,例如,分組時只反序列化記錄中需要的部分,完全處理二進位制資料,以及整個查詢優化
  • 同樣的查詢/程式可用於有界和無界源
  • 流和批次處理的高效執行,這意味著對於有界執行,我們可以使用DataSet API使用的執行模型,對於流用例,使用DataStrem API的執行模型。這對使用者來說是透明的。
  • 沒有低階運算元API,即沒有計時器、狀態
  • 不控制生成的執行DAG→查詢優化器會阻止儲存點相容性

自然會出現這樣的問題:「為什麼社群最初不擴充套件DataSet API來處理無界/流式的工作負載,而是新增DataStream API ?」簡單的回答是,我們當時沒有花時間去思考一個API如何同時服務於兩個用例。

為什麼有太多的api不好呢?

我們看到當前局勢存在兩個主要問題:

當需要物理API時,重用Flink應用程式的無界處理和有界處理是不現實的:

我們認為,對於使用者來說,編寫一個管道來分析流資料/無界資料,然後希望重用相同的程式碼來處理有界資料/批次處理資料是很常見的。例如,當你想處理S3的歷史資料時,實時管道會從Kafka讀取資料。理論上,可以對有界源使用DataStream API,但無法獲得有效的執行或容錯行為。如果出現故障,整個管道必須重新啟動。這與DataSet API的執行模型不同,在該模型中,只需要重啟單個操作或連線的子圖,因為我們可以保留操作的中間結果。

如果您事先知道所有的輸入,那麼使用事件時間語意就會容易得多。水印可以總是「完美」的,因為沒有早期或晚期資料,我們用於批次處理式執行的演演算法和資料結構可以考慮到這一點。

DataSet和DataStream API有不同的可用聯結器集,因為它們使用不同的API來定義源和接收。例如,你不能用批次處理型別的作業從Kafka讀取一個有界的區間。

最後,我們認為DataStream API的事件時間/視窗特性對於批次處理也很有用。例如,當您想要處理時間序列資料時。目前,您可以使用DataStream API並處理低於標準的執行行為,或者使用DataSet API並使用排序/分組手動實現視窗。

使用者必須提前在api之間做出選擇:

這增加了認知負荷,使Flink對新使用者來說更不容易接近。如果他們一開始就做出了錯誤的選擇,那麼如果沒有大量的時間投資,他們將無法在以後轉換。

另一個方面是,想要採用Flink的大型組織可能會因為不得不對工程師進行兩種不同api及其潛在語意差異的培訓而受挫,例如什麼是延遲,什麼是事件時間,以及它是否與批次處理相關等。

修改建議

我們建議棄用DataSet API,而使用Table API/SQL和DataStream API。為了實現這一點,我們需要增強Table API/SQL和DataStream API,使其成為以前使用DataSet API的情況下可用的替代品。我們將在這裡概述所需的更改,但將更具體的計劃推遲到後續的FLIPs。對於這個提議,我們只是想讓社群就棄用DataSet API的總體想法達成共識,並概述其他API所需的變化。

對「倖存者」api的更改

Table/SQL API:

  • 必須容易在程式碼中內聯定義源/接收器。這在FLIP-129:重構描述符API中進行了介紹,以在表API中註冊聯結器。
  • 我們應該在Table上有易於使用的「命令式」操作,也就是應該有「人體工程學」map/filter/flatMap。這些操作應該是面向行/記錄的,而不是常規Table API操作的面向列的性質。這樣使用者就不必學習表示式DSL語法來編寫操作。
  • 此外,我們還希望棄用/刪除遺留表API批次處理計劃器以及批執行環境,因為它們與DataSet API互操作

DataStream資料API:

  • 我們需要一個適用於有界和無界源的源API。這在FLIP-27:重構源介面中有涉及。
  • 我們需要一個適用於無界和有界源的接收器API。這是由FLIP-143:統一匯聚API覆蓋的
  • 我們需要定義一組通用的執行語意,用於批次處理和流執行,這包括重新考慮DataStream API中的一些決策,使它們在一個統一的世界中工作。這在FLIP-134: DataStream API的批次處理執行中得到了介紹
  • 當拓撲有界時,我們需要為DataStream程式使用高效的批次處理式執行。這在FLIP-140中有涉及:為有界鍵控流引入批次處理樣式的執行
  • 特別是對於機器學習用例,我們需要對迭代計算的健壯支援。目前DataStream API中對迭代的支援應該被認為是實驗性的,它不像DataSet API那樣支援動態終止標準。然而,我認為我們需要在後續FLIP中解決這個問題。

哪些用例應該使用什麼API/SDK

我們目前還沒有明確的指南來指導使用者應該使用哪種API。我們需要就建議達成一致,然後在檔案和一般行銷中積極推廣它們。這可能會以決策樹或其他圖形化決策工具/應用的形式出現。

我們目前的想法總結如下:

  • 如果你有一個模式,沒有「低階」操作→SQL/Table
  • 如果你需要顯式控制執行圖、操作、操作中的狀態→使用DataStream API

也就是說,應該可以在Table API和DataStream API之間自由轉換。FLIP-136:改善DataStream和Table API之間的互操作性使這些工作更加具體。

相容性、棄用和遷移計劃

DataSet API應該在檔案和程式碼中標記為已棄用,並描述專案的未來方向。在即將到來的版本中。

  • 使用者有足夠的時間將現有的用例遷移到其他API,
  • 我們確信剩餘的API足以覆蓋DataSet API的用例,我們就應該刪除DataSet API。

這取決於上面提到的後續FLIPs,所以當滿足上面概述的條件時,這個FLIPs可以被認為是完整的。

重要的是要記住,我們不能簡單地將DataSet API從一個版本移到下一個版本。這將是一個較長的過程,我們需要確保DataSet API的現有使用者能夠遷移並進行遷移。有些公司在DataSet API上投入了大量資金,但他們不能把它們拋在後面。

拒絕選擇

我們認為,如果可用api的重疊像DataStream和DataSet api那樣明顯,那麼除了減少可用api的數量別無選擇。理論上我們可以棄用DataStream API,支援DataSet API,但我們認為DataStream API是更廣泛使用的API,而且目前它的功能也更齊全(請參閱事件時間處理和視窗)。這也與「批次處理是流的一部分,批次處理是流處理的嚴格子集」的思想產生了很好的共鳴。

關注gzh HEY DATA 一起交流更多。