Flink源碼閱讀(13)--- Flink 不同版本新特性整理

一. Flink 1.9 新特性

總的變更:https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12315522&version=12344601
發布時間:2019.8.22

1. Flink Table API/SQL

1.1 Flink SQL DDL 支持

?? 到目前為止,Flink SQL 已經支持 DML 語句(如 SELECT,INSERT)。但是外部表(table source 和 table sink)必須通過 Java/Scala 代碼或配置文件的方式注冊。1.9 版本中,支持 SQL DDL 語句的方式注冊和刪除表(CREATE TABLE,DROP TABLE)。不過目前還沒有增加流特定的語法擴展來定義時間戳抽取和 watermark 生成策略等。流式的需求也將會在下一版本中完整支持。

flink1.6

?? - 只支持dml(select和insert)

flink1.9

?? - define/alter/delete sink/source table

?? - define/alter/delete view

?? - define/replace/delete 用戶定義的類型type(eg: CREATE [ OR REPLACE ] TYPE name AS fieldType

?? - 可以加載外部的function來作為udf使用

1.2 新 Blink Table/SQL Planner

1.2.1 現在有兩個插件化的查詢處理器來執行 Table API 和 SQL:1.9 以前的 Flink 處理器和新的基于 Blink 的處理器。兩個查詢處理器之間的語義和功能大部分是一致的,但未完全對齊。不過,Blink 的查詢處理器尚未完全集成。因此,1.9 之前的 Flink 處理器仍然是 1.9 版本的默認處理器,建議用于生產設置。

1.2.2 基于 Blink 的查詢處理器還提供了更強大的流處理能力,包括一些社區期待已久的新功能(如維表 Join,TopN,去重)和聚合場景緩解數據傾斜的優化,以及內置更多常用的函數。

1.2.3 使用限制(非常細節的東西),在后面的版本會支持:

??- batch job如果使用blink planner,需要使用TableEnvironment,不能用BatchTableEnvironment。

??- StreamTableSink的實現類需要實現consumeDataStream()方法,而不是emitDataStream()方法。

??- 不支持Table.flatAggregate。

??- batch job不支持session/count window。

??- Blink planner只支持新Catalog API,不再支持ExternalCatalog。

1.3 Table API / SQL 的其他改進

1.3.1 重構 Table API / SQL 的類型系統

??Flink 1.9 實現了一個新的數據類型系統,以便從 Table API 中移除對 Flink TypeInformation的依賴,并提高其對 SQL 標準的遵從性,不過還在進行中,預計將在下一版本1.10完工,并且在 Flink 1.9 中,UDF 尚未移植到新的類型系統上。如果直接升級到1.9,等1.10完善之后,改動還會比較大。由于blink planner和新的數據類型系統是同時進行的,新的planner并沒有支持所有的數據類型,并且以后新的planner可能對有的數據類型不再進行支持(風險點)。

1.3.2 為 Table API / SQL 的 Java 用戶去除 Scala 依賴

1.3.3 Table API 的多列和多行轉換

1.3.4 重構和統一 Catalog API

?? 在此之前,通過 Table API 或 SQL 定義的表都無法持久化保存;從 Flink 1.9 起,這些表的元數據可以被持久化到 catalog 中。這意味著用戶可以在 Hive Metastore Catalog 中創建 Kafka 表,并在 query 中直接引用該表。

1.3.5 Hive 集成預覽(beta)

??最近,社區開始為 Flink Table API 和 SQL 實現一個連接到 Hive Metastore 的外部 catalog。在 Flink 1.9 中,用戶能夠查詢和處理存儲在 Hive 中多種格式的數據。 Hive 集成還包括支持在 Flink Table API / SQL 中使用 Hive 的 UDF。

??在以前,Table API / SQL 中定義的表一直是臨時的。新的 catalog 連接器允許在 Metastore 中持久化存儲那些使用 SQL DDL 語句創建的表。這意味著可以直接連接到 Metastore 并注冊一個表,例如,Kafka topic 的表。從現在開始,只要 catalog 連接到 Metastore,就可以查詢該表。

??請注意 Flink 1.9 中提供的 Hive 支持目前還是實驗性的,下一個版本中將穩定這些功能。

1.3.6 為hbase增加Upsert table sink factory

1.3.7 為Table API增加map、flatmap、aggregate算子

2. Runtime & core

2.1 細粒度批作業恢復 (FLIP-1)
  • 批作業(DataSet、Table API 和 SQL)從 task 失敗中恢復的時間被顯著縮短。在 Flink 1.9 之前,批處理作業中的 task 失敗是通過取消所有 task 并重新啟動整個作業來恢復的,即作業從頭開始,所有進度都會廢棄。在 1.9 版本中,Flink 將中間結果保留在網絡 shuffle 的邊緣,并使用這些數據恢復僅受故障影響的 tasks,即處在同一個 failover region (故障區)的 tasks。

  • “Region” 的故障策略也能同時提升 “embarrassingly parallel” 類型的流作業恢復速度,也就是沒有任何像 keyBy、rebalance 等 shuffle 的作業。當這種作業在恢復時,只有受影響的故障區 task 需要重啟。對于其他類型的流作業,故障恢復行為與之前的版本一樣。

2.2 Stop-with-Savepoint,https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=103090212

2.2.1 Rest API中,增加SUSPEND/TERMINATE命令。CheckpointType中增加了一種SYNC_SAVEPOINT類型,在suspending/terminating 作業的時候,savepoint采用同步的方式來制作。

2.2.2 “Cancel-with-savepoint”是停止、重啟或升級 Flink 作業的一個常用操作。然而,當前的實現并沒有保證輸出到 exactly-once sink 的外部存儲的數據持久化。為了改進停止作業時的端到端語義,Flink 1.9 引入了一種新的 SUSPEND 模式,可以帶 savepoint 停止作業,保證了輸出數據的一致性。可以使用 Flink CLI 來 suspend 一個作業:bin/flink stop -p [:targetSavepointDirectory] :jobId。最終作業的狀態會在成功時設置成 FINISHED 狀態,方便用戶區別操作是否失敗。

備注:原來是cancel命令可以指定做不做save point,現在cancel/stop命令中都可以指定做不做save point,只是stop的時候會先掛起job。

2.3 State Processing API, 從1.9開始,Flink state可以對外暴露,在外部可以使用client來查詢(beta)。https://ci.apache.org/projects/flink/flink-docs-stable/dev/stream/state/queryable_state.html
2.4 在SQL-Client 的yaml配置文件中支持外部catalog。
2.5 source增加對 Parquet file的支持.
2.6 重構 Flink WebUI。重新設計的 UI 是 1.9.0 的默認版本,不過仍保留了切換到舊版 WebUI 的按鈕。

二. Flink 1.10 新特性

  1. flink1.10新特性
    發布時間:2020.2.11
1.1 內存管理和配置優化

原來的問題
?? 原來TaskExecutor內存配置有缺點,難做資源利用優化,比如:
???? - 批和流的配置模型不同;
???? - 流計算場景,比如RocksDB這種不是基于堆內存的state backend,需要用戶進行復雜的配置

優化點
?? 1. 管理的內存拓展
???? - 批作業仍然可以繼續使用heap和off-heap內存。
???? - 流作業如果使用RocksDBStateBackend,只能使用off-heap內存
???? - 為了批流集群配置統一,管理內存只能使用off-heap

?? 2. 簡化RocksDB配置
???? - 配置RocksDB原來需要手動調試,比如減小JVM堆大小、設置Flink使用的堆外內存。現在Flink的開箱配置即可完成,且只需要簡單地調整managed內存的大小即可調整RocksDBStateBackend的內存預算。

1.2 job提交的邏輯統一

?? 原來提交作業是由環境變量負責的,并且和部署方式有關(比如:Yarn,Kubernetes, Mesos)。
?? 在flink1.10,作業提交邏輯抽象出Executor接口,新增加的ExecutorCLI為任意一個執行目標提供了統一的配置參數。另外,引入JobClient來獲取JobExecutionResult,這樣結果獲取和作業的提交邏輯解耦。

1.3 原生Kubernetes集成(Beta)
1.4 Table API/SQL:hive集成已經可以在生產環境使用

?? Flink 1.9 推出了beta Hive 集成。
?? 1. Batch SQL 原生分區支持
?? 2. flink1.10 hive集成還引入許多數據讀取方面的優化
???? - 投影下推
???? - limit下推
???? - 讀取數據時orc向量化

?? 3. SQL DDL中支持watermark 和計算列
?? 4. 其他DDL的拓展
???? - UDF
?????? CREATE [TEMPORARY|TEMPORARY SYSTEM] FUNCTION

三. Flink 1.11 新特性

  1. flink1.11新特性,該部分內容轉自 Flink 1.11.0 發布,有哪些值得關注的新特性?
    發布時間:2020.7.7

改進一: 生態完善和易用性提升

1 Table & SQL 支持 Change Data Capture(CDC)

CDC 被廣泛使用在復制數據、更新緩存、微服務間同步數據、審計日志等場景,很多公司都在使用開源的 CDC 工具,如 MySQL CDC。通過 Flink 支持在 Table & SQL 中接入和解析 CDC 是一個強需求,在過往的很多討論中都被提及過,可以幫助用戶以實時的方式處理 changelog 流,進一步擴展 Flink 的應用場景,例如把 MySQL 中的數據同步到 PG 或 ElasticSearch 中,低延時的 temporal join 一個 changelog 等。

除了考慮到上面的真實需求,Flink 中定義的“Dynamic Table”概念在流上有兩種模型:append 模式和 update 模式。通過 append 模式把流轉化為“Dynamic Table”在之前的版本中已經支持,因此在 1.11.0 中進一步支持 update 模式也從概念層面完整的實現了“Dynamic Table”。

image.png

為了支持解析和輸出 changelog,如何在外部系統和 Flink 系統之間編解碼這些更新操作是首要解決的問題。考慮到 source 和 sink 是銜接外部系統的一個橋梁,因此 FLIP-95 在定義全新的 Table source 和 Table sink 接口時解決了這個問題。

在公開的 CDC 調研報告中,Debezium 和 Canal 是用戶中最流行使用的 CDC 工具,這兩種工具用來同步 changelog 到其它的系統中,如消息隊列。據此,FLIP-105 首先支持了 Debezium 和 Canal 這兩種格式,而且 Kafka source 也已經可以支持解析上述格式并輸出更新事件,在后續的版本中會進一步支持 Avro(Debezium) 和 Protobuf(Canal)。

CREATE TABLE my_table (  
...) WITH (  
'connector'='...', -- e.g. 'kafka'  
'format'='debezium-json',  
'debezium-json.schema-include'='true' -- default: false (Debezium can be configured to include or exclude the message schema)  
'debezium-json.ignore-parse-errors'='true' -- default: false
);

2 Table & SQL 支持 JDBC Catalog

1.11.0 之前,用戶如果依賴 Flink 的 source/sink 讀寫關系型數據庫或讀取 changelog 時,必須要手動創建對應的 schema。而且當數據庫中的 schema 發生變化時,也需要手動更新對應的 Flink 作業以保持一致和類型匹配,任何不匹配都會造成運行時報錯使作業失敗。用戶經常抱怨這個看似冗余且繁瑣的流程,體驗極差。

實際上對于任何和 Flink 連接的外部系統都可能有類似的上述問題,在 1.11.0 中重點解決了和關系型數據庫對接的這個問題。FLIP-93 提供了 JDBC catalog 的基礎接口以及 Postgres catalog 的實現,這樣方便后續實現與其它類型的關系型數據庫的對接。

1.11.0 版本后,用戶使用 Flink SQL 時可以自動獲取表的 schema 而不再需要輸入 DDL。除此之外,任何 schema 不匹配的錯誤都會在編譯階段提前進行檢查報錯,避免了之前運行時報錯造成的作業失敗。這是提升易用性和用戶體驗的一個典型例子。

3 Hive 實時數倉

從 1.9.0 版本開始 Flink 從生態角度致力于集成 Hive,目標打造批流一體的 Hive 數倉。經過前兩個版本的迭代,已經達到了 batch 兼容且生產可用,在 TPC-DS 10T benchmark 下性能達到 Hive 3.0 的 7 倍以上。

1.11.0 在 Hive 生態中重點實現了實時數倉方案,改善了端到端流式 ETL 的用戶體驗,達到了批流一體 Hive 數倉的目標。同時在兼容性、性能、易用性方面也進一步進行了加強。

在實時數倉的解決方案中,憑借 Flink 的流式處理優勢做到實時讀寫 Hive:

  • Hive 寫入:FLIP-115 完善擴展了 FileSystem connector 的基礎能力和實現,Table/SQL 層的 sink 可以支持各種格式(CSV、Json、Avro、Parquet、ORC),而且支持 Hive table 的所有格式。
  • Partition 支持:數據導入 Hive 引入 partition 提交機制來控制可見性,通過sink.partition-commit.trigger 控制 partition 提交的時機,通過 sink.partition-commit.policy.kind 選擇提交策略,支持 SUCCESS 文件和 metastore 提交。
  • Hive 讀取:實時化的流式讀取 Hive,通過監控 partition 生成增量讀取新 partition,或者監控文件夾內新文件生成來增量讀取新文件。

在 Hive 可用性方面的提升:

  • FLIP-123 通過 Hive Dialect 為用戶提供語法兼容,這樣用戶無需在 Flink 和 Hive 的 CLI 之間切換,可以直接遷移 Hive 腳本到 Flink 中執行。
  • 提供 Hive 相關依賴的內置支持,避免用戶自己下載所需的相關依賴。現在只需要單獨下載一個包,配置 HADOOP_CLASSPATH 就可以運行。
  • 在 Hive 性能方面,1.10.0 中已經支持了 ORC(Hive 2+)的向量化讀取,1.11.0 中我們補全了所有版本的 Parquet 和 ORC 向量化支持來提升性能。

3 全新 Source API

前面也提到過,source 和 sink 是 Flink 對接外部系統的一個橋梁,對于完善生態、可用性及端到端的用戶體驗是很重要的環節。社區早在一年前就已經規劃了 source 端的徹底重構,從 FLIP-27 的 ID 就可以看出是很早的一個 feature。但是由于涉及到很多復雜的內部機制和考慮到各種 source connector 的實現,設計上需要考慮的很全面。從 1.10.0 就開始做 POC 的實現,最終趕上了 1.11.0 版本的發布。

先簡要回顧下 source 之前的主要問題:

  • 對用戶而言,在 Flink 中改造已有的 source 或者重新實現一個生產級的 source connector 不是一件容易的事情,具體體現在沒有公共的代碼可以復用,而且需要理解很多 Flink 內部細節以及實現具體的 event time 分配、watermark 產出、idleness 監測、線程模型等。
  • 批和流的場景需要實現不同的 source。
  • partitions/splits/shards 概念在接口中沒有顯式表達,比如 split 的發現邏輯和數據消費都耦合在 source function 的實現中,這樣在實現 Kafka 或 Kinesis 類型的 source 時增加了復雜性。
  • 在 runtime 執行層,checkpoint 鎖被 source function 搶占會帶來一系列問題,框架很難進行優化。

FLIP-27 在設計時充分考慮了上述的痛點:

image.png
  • 首先在 Job Manager 和 Task Manager 中分別引入兩種不同的組件 Split Enumerator 和 Source reader,解耦 split 發現和對應的消費處理,同時方便隨意組合不同的策略。比如現有的 Kafka connector 中有多種不同的 partition 發現策略和實現耦合在一起,在新的架構下,我們只需要實現一種 source reader,就可以適配多種 split enumerator 的實現來對應不同的 partition 發現策略。
  • 在新架構下實現的 source connector 可以做到批流統一,唯一的小區別是對批場景的有限輸入,split enumerator 會產出固定數量的 split 集合并且每個 split 都是有限數據集;對于流場景的無限輸入,split enumerator 要么產出無限多的 split 或者 split 自身是無限數據集。
  • 復雜的 timestamp assigner 以及 watermark generator 透明的內置在 source reader 模塊內運行,對用戶來說是無感知的。這樣用戶如果想實現新的 source connector,一般不再需要重復實現這部分功能。

目前 Flink 已有的 source connector 會在后續的版本中基于新架構來重新實現,legacy source 也會繼續維護幾個版本保持兼容性,用戶也可以按照 release 文檔中的說明來嘗試體驗新 source 的開發。

4 PyFlink 生態

眾所周知,Python 語言在機器學習和數據分析領域有著廣泛的使用。Flink 從 1.9.0 版本開始發力兼容 Python 生態,Python 和 Flink 合力為 PyFlink,把 Flink 的實時分布式處理能力輸出給 Python 用戶。前兩個版本 PyFlink 已經支持了 Python Table API 和 UDF,在 1.11.0 中擴大對 Python 生態庫 Pandas 的支持以及和 SQL DDL/Client 的集成,同時 Python UDF 性能有了極大的提升。

具體來說,之前普通的 Python UDF 每次調用只能處理一條數據,而且在 Java 端和 Python 端都需要序列化/反序列化,開銷很大。1.11.0 中 Flink 支持在 Table & SQL 作業中自定義和使用向量化 Python UDF,用戶只需要在 UDF 修飾中額外增加一個參數 udf_type=“pandas” 即可。這樣帶來的好處是:

  • 每次調用可以處理 N 條數據。
  • 數據格式基于 Apache Arrow,大大降低了 Java、Python 進程之間的序列化/反序列化開銷。
  • 方便 Python 用戶基于 Numpy 和 Pandas 等數據分析領域常用的 Python 庫,開發高性能的 Python UDF。

除此之外,1.11.0 中 PyFlink 還支持:

  • PyFlink table 和 Pandas DataFrame 之間無縫切換(FLIP-120),增強 Pandas 生態的易用性和兼容性。
  • Table & SQL 中可以定義和使用 Python UDTF(FLINK-14500),不再必需 Java/Scala UDTF。
  • Cython 優化 Python UDF 的性能(FLIP-121),對比 1.10.0 可以提升 30 倍。
  • Python UDF 中用戶自定義 metric(FLIP-112),方便監控和調試 UDF 的執行。

上述解讀的都是側重 API 層面,用戶開發作業可以直接感知到的易用性的提升。下面我們看看執行引擎層在 1.11.0 中都有哪些值得關注的變化。

改進二. 生產可用性和穩定性提升

1 支持 application 模式和 Kubernetes 增強

1.11.0 版本前,Flink 主要支持如下兩種模式運行:

  • Session 模式:提前啟動一個集群,所有作業都共享這個集群的資源運行。優勢是避免每個作業單獨啟動集群帶來的額外開銷,缺點是隔離性稍差。如果一個作業把某個 Task Manager(TM)容器搞掛,會導致這個容器內的所有作業都跟著重啟。雖然每個作業有自己獨立的 Job Manager(JM)來管理,但是這些 JM 都運行在一個進程中,容易帶來負載上的瓶頸。
  • Per-job 模式:為了解決 session 模式隔離性差的問題,每個作業根據資源需求啟動獨立的集群,每個作業的 JM 也是運行在獨立的進程中,負載相對小很多。

以上兩種模式的共同問題是需要在客戶端執行用戶代碼,編譯生成對應的 Job Graph 提交到集群運行。在這個過程需要下載相關 jar 包并上傳到集群,客戶端和網絡負載壓力容易成為瓶頸,尤其當一個客戶端被多個用戶共享使用。

1.11.0 中引入了 application 模式(FLIP-85)來解決上述問題,按照 application 粒度來啟動一個集群,屬于這個 application 的所有 job 在這個集群中運行。核心是 Job Graph 的生成以及作業的提交不在客戶端執行,而是轉移到 JM 端執行,這樣網絡下載上傳的負載也會分散到集群中,不再有上述 client 單點上的瓶頸。

用戶可以通過 bin/flink run-application 來使用 application 模式,目前 Yarn 和 Kubernetes(K8s)都已經支持這種模式。Yarn application 會在客戶端將運行作業需要的依賴都通過 Yarn Local Resource 傳遞到 JM。K8s application 允許用戶構建包含用戶 jar 與依賴的鏡像,同時會根據作業自動創建 TM,并在結束后銷毀整個集群,相比 session 模式具有更好的隔離性。K8s 不再有嚴格意義上的 per-job 模式,application 模式相當于 per-job 在集群進行提交作業的實現。

除了支持 application 模式,Flink 原生 K8s 在 1.11.0 中還完善了很多基礎的功能特性(FLINK-14460),以達到生產可用性的標準。例如 Node Selector、Label、Annotation、Toleration 等。為了更方便的與 Hadoop 集成,也支持根據環境變量自動掛載 Hadoop 配置的功能。

2 Checkpoint & Savepoint 優化

checkpoint 和 savepoint 機制一直是 Flink 保持先進性的核心競爭力之一,社區在這個領域的改動很謹慎,最近的幾個大版本中幾乎沒有大的功能和架構上的調整。在用戶郵件列表中,我們經常能看到用戶反饋和抱怨的相關問題:比如 checkpoint 長時間做不出來失敗,savepoint 在作業重啟后不可用等等。1.11.0 有選擇的解決了一些這方面的常見問題,提高生產可用性和穩定性。

1.11.0 之前, savepoint 中 meta 數據和 state 數據分別保存在兩個不同的目錄中,這樣如果想遷移 state 目錄很難識別這種映射關系,也可能導致目錄被誤刪除,對于目錄清理也同樣有麻煩。1.11.0 把兩部分數據整合到一個目錄下,這樣方便整體轉移和復用。另外,之前 meta 引用 state 采用的是絕對路徑,這樣 state 目錄遷移后路徑發生變化也不可用,1.11.0 把 state 引用改成了相對路徑解決了這個問題(FLINK-5763),這樣 savepoint 的管理維護、復用更加靈活方便。

實際生產環境中,用戶經常遭遇 checkpoint 超時失敗、長時間不能完成帶來的困擾。一旦作業 failover 會造成回放大量的歷史數據,作業長時間沒有進度,端到端的延遲增加。1.11.0 從不同維度對 checkpoint 的優化和提速做了改進,目標實現分鐘甚至秒級的輕量型 checkpoint。

首先,增加了 Checkpoint Coordinator 通知 task 取消 checkpoint 的機制(FLINK-8871),這樣避免 task 端還在執行已經取消的 checkpoint 而對系統帶來不必要的壓力。同時 task 端放棄已經取消的 checkpoint,可以更快的參與執行 coordinator 新觸發的 checkpoint,某種程度上也可以避免新 checkpoint 再次執行超時而失敗。這個優化也對后面默認開啟 local recovery 提供了便利,task 端可以及時清理失效 checkpoint 的資源。

其次,在反壓場景下,整個數據鏈路堆積了大量 buffer,導致 checkpoint barrier 排在數據 buffer 后面,不能被 task 及時處理對齊,也就導致了 checkpoint 長時間不能執行。1.11.0 中從兩個維度對這個問題進行解決:

1)嘗試減少數據鏈路中的 buffer 總量(FLINK-16428),這樣 checkpoint barrier 可以盡快被處理對齊。

  • 上游輸出端控制單個 sub partition 堆積 buffer 的最大閾值(backlog),避免負載不均場景下單個鏈路上堆積大量 buffer。
  • 在不影響網絡吞吐性能的情況下合理修改上下游默認的 buffer 配置。
  • 上下游數據傳輸的基礎協議進行了調整,允許單個數據鏈路可以配置 0 個獨占 buffer 而不死鎖,這樣總的 buffer 數量和作業并發規模解耦。根據實際需求在吞吐性能和 checkpoint 速度兩者之間權衡,自定義 buffer 配比。

這個優化有一部分工作已經在 1.11.0 中完成,剩余部分會在下個版本繼續推進完成。

2)實現了全新的 unaligned checkpoint 機制(FLIP-76)從根本上解決了反壓場景下 checkpoint barrier 對齊的問題。實際上這個想法早在 1.10.0 版本之前就開始醞釀設計,由于涉及到很多模塊的大改動,實現機制和線程模型也很復雜。我們實現了兩種不同方案的原型 POC 進行了測試、性能對比,確定了最終的方案,因此直到 1.11.0 才完成了 MVP 版本,這也是 1.11.0 中執行引擎層唯一的一個重量級 feature。其基本思想可以概括為:

  • Checkpoint barrier 跨數據 buffer 傳輸,不在輸入輸出隊列排隊等待處理,這樣就和算子的計算能力解耦,barrier 在節點之間的傳輸只有網絡延時,可以忽略不計。
  • 每個算子多個輸入鏈路之間不需要等待 barrier 對齊來執行 checkpoint,第一個到的 barrier 就可以提前觸發 checkpoint,這樣可以進一步提速 checkpoint,不會因為個別鏈路的延遲而影響整體。
  • 為了和之前 aligned checkpoint 的語義保持一致,所有未被處理的輸入輸出數據 buffer 都將作為 channel state 在 checkpoint 執行時進行快照持久化,在 failover 時連同 operator state 一同進行恢復。換句話說,aligned 機制保證的是 barrier 前面所有數據必須被處理完,狀態實時體現到 operator state 中;而 unaligned 機制把 barrier 前面的未處理數據所反映的 operator state 延后到 failover restart 時通過 channel state 回放進行體現,從狀態恢復的角度來說最終都是一致的。注意這里雖然引入了額外的 in-flight buffer 的持久化,但是這個過程實際是在 checkpoint 的異步階段完成的,同步階段只是進行了輕量級的 buffer 引用,所以不會過多占用算子的計算時間而影響吞吐性能。
image.png

Unaligned checkpoint 在反壓嚴重的場景下可以明顯加速 checkpoint 的完成時間,因為它不再依賴于整體的計算吞吐能力,而和系統的存儲性能更加相關,相當于計算和存儲的解耦。但是它的使用也有一定的局限性,它會增加整體 state 的大小,對存儲 IO 帶來額外的開銷,因此在 IO 已經是瓶頸的場景下就不太適合使用 unaligned checkpoint 機制。

1.11.0 中 unaligned checkpoint 還沒有作為默認模式,需要用戶手動配置來開啟,并且只在 exactly-once 模式下生效。但目前還不支持 savepoint 模式,因為 savepoint 涉及到作業的 rescale 場景,channel state 目前還不支持 state 拆分,在后面的版本會進一步支持,所以 savepoint 目前還是會使用之前的 aligned 模式,在反壓場景下有可能需要很長時間才能完成。

四. Flink 1.12 新特性

  1. flink1.12新特性,該部分內容轉自 官宣 | Apache Flink 1.12.0 正式發布,流批一體真正統一運行!
    發布時間:2020.12.10

DataStream API 支持批執行模式

Flink 的核心 API 最初是針對特定的場景設計的,盡管 Table API / SQL 針對流處理和批處理已經實現了統一的 API,但當用戶使用較底層的 API 時,仍然需要在批處理(DataSet API)和流處理(DataStream API)這兩種不同的 API 之間進行選擇。鑒于批處理是流處理的一種特例,將這兩種 API 合并成統一的 API,有一些非常明顯的好處,比如:

· 可復用性:作業可以在流和批這兩種執行模式之間自由地切換,而無需重寫任何代碼。因此,用戶可以復用同一個作業,來處理實時數據和歷史數據。
· 維護簡單:統一的 API 意味著流和批可以共用同一組 connector,維護同一套代碼,并能夠輕松地實現流批混合執行,例如 backfilling 之類的場景。

考慮到這些優點,社區已朝著流批統一的 DataStream API 邁出了第一步:支持高效的批處理(FLIP-134)。從長遠來看,這意味著 DataSet API 將被棄用(FLIP-131),其功能將被包含在 DataStream API 和 Table API / SQL 中。

■ 有限流上的批處理

您已經可以使用 DataStream API 來處理有限流(例如文件)了,但需要注意的是,運行時并不“知道”作業的輸入是有限的。為了優化在有限流情況下運行時的執行性能,新的 BATCH 執行模式,對于聚合操作,全部在內存中進行,且使用 sort-based shuffle(FLIP-140)和優化過的調度策略(請參見 Pipelined Region Scheduling 了解更多詳細信息)。因此,DataStream API 中的 BATCH 執行模式已經非常接近 Flink 1.12 中 DataSet API 的性能。有關性能的更多詳細信息,請查看 FLIP-140。

1.png

在 Flink 1.12 中,默認執行模式為 STREAMING,要將作業配置為以 BATCH 模式運行,可以在提交作業的時候,設置參數 execution.runtime-mode:

$ bin/flink run -Dexecution.runtime-mode=BATCH examples/streaming/WordCount.jar

或者通過編程的方式:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setRuntimeMode(RuntimeMode.BATCH);

注意:盡管 DataSet API 尚未被棄用,但我們建議用戶優先使用具有 BATCH 執行模式的 DataStream API 來開發新的批作業,并考慮遷移現有的 DataSet 作業。

新的 Data Sink API (Beta)

之前發布的 Flink 版本中[1],已經支持了 source connector 工作在流批兩種模式下,因此在 Flink 1.12 中,社區著重實現了統一的 Data Sink API(FLIP-143)。新的抽象引入了 write/commit 協議和一個更加模塊化的接口。Sink 的實現者只需要定義 what 和 how:SinkWriter,用于寫數據,并輸出需要 commit 的內容(例如,committables);Committer 和 GlobalCommitter,封裝了如何處理 committables。框架會負責 when 和 where:即在什么時間,以及在哪些機器或進程中 commit。

222.png

這種模塊化的抽象允許為 BATCH 和 STREAMING 兩種執行模式,實現不同的運行時策略,以達到僅使用一種 sink 實現,也可以使兩種模式都可以高效執行。Flink 1.12 中,提供了統一的 FileSink connector,以替換現有的 StreamingFileSink connector (FLINK-19758)。其它的 connector 也將逐步遷移到新的接口。

基于 Kubernetes 的高可用 (HA) 方案

Flink 可以利用 Kubernetes 提供的內置功能來實現 JobManager 的 failover,而不用依賴 ZooKeeper。為了實現不依賴于 ZooKeeper 的高可用方案,社區在 Flink 1.12(FLIP-144)中實現了基于 Kubernetes 的高可用方案。該方案與 ZooKeeper 方案基于相同的接口[3],并使用 Kubernetes 的 ConfigMap[4] 對象來處理從 JobManager 的故障中恢復所需的所有元數據。關于如何配置高可用的 standalone 或原生 Kubernetes 集群的更多詳細信息和示例,請查閱文檔[5]。

注意:需要注意的是,這并不意味著 ZooKeeper 將被刪除,這只是為 Kubernetes 上的 Flink 用戶提供了另外一種選擇。

其它功能改進

■ 將現有的 connector 遷移到新的 Data Source API

在之前的版本中,Flink 引入了新的 Data Source API(FLIP-27),以允許實現同時適用于有限數據(批)作業和無限數據(流)作業使用的 connector 。在 Flink 1.12 中,社區從 FileSystem connector(FLINK-19161)出發,開始將現有的 source connector 移植到新的接口。

注意: 新的 source 實現,是完全不同的實現,與舊版本的實現不兼容。

■ Pipelined Region 調度 (FLIP-119)

在之前的版本中,Flink 對于批作業和流作業有兩套獨立的調度策略。Flink 1.12 版本中,引入了統一的調度策略, 該策略通過識別 blocking 數據傳輸邊,將 ExecutionGraph 分解為多個 pipelined region。這樣一來,對于一個 pipelined region 來說,僅當有數據時才調度它,并且僅在所有其所需的資源都被滿足時才部署它;同時也可以支持獨立地重啟失敗的 region。對于批作業來說,新策略可顯著地提高資源利用率,并消除死鎖。

■ 支持 Sort-Merge Shuffle (FLIP-148)

為了提高大規模批作業的穩定性、性能和資源利用率,社區引入了 sort-merge shuffle,以替代 Flink 現有的實現。這種方案可以顯著減少 shuffle 的時間,并使用較少的文件句柄和文件寫緩存(這對于大規模批作業的執行非常重要)。在后續版本中(FLINK-19614),Flink 會進一步優化相關性能。

注意:該功能是實驗性的,在 Flink 1.12 中默認情況下不啟用。要啟用 sort-merge shuffle,需要在 TaskManager 的網絡配置[6]中設置合理的最小并行度。

■ Flink WebUI 的改進 (FLIP-75)

作為對上一個版本中,Flink WebUI 一系列改進的延續,Flink 1.12 在 WebUI 上暴露了 JobManager 內存相關的指標和配置參數(FLIP-104)。對于 TaskManager 的指標頁面也進行了更新,為 Managed Memory、Network Memory 和 Metaspace 添加了新的指標,以反映自 Flink 1.10(FLIP-102)開始引入的 TaskManager 內存模型的更改[7]。

Table API/SQL: SQL Connectors 中的 Metadata 處理

如果可以將某些 source(和 format)的元數據作為額外字段暴露給用戶,對于需要將元數據與記錄數據一起處理的用戶來說很有意義。一個常見的例子是 Kafka,用戶可能需要訪問 offset、partition 或 topic 信息、讀寫 kafka 消息中的 key 或 使用消息 metadata中的時間戳進行時間相關的操作。

在 Flink 1.12 中,Flink SQL 支持了元數據列用來讀取和寫入每行數據中 connector 或 format 相關的列(FLIP-107)。這些列在 CREATE TABLE 語句中使用 METADATA(保留)關鍵字來聲明。

CREATE TABLE kafka_table (
id BIGINT,
name STRING,
event_time TIMESTAMP(3) METADATA FROM 'timestamp', -- access Kafka 'timestamp' metadata
headers MAP METADATA -- access Kafka 'headers' metadata
) WITH (
'connector' = 'kafka',
'topic' = 'test-topic',
'format' = 'avro'
);

在 Flink 1.12 中,已經支持 Kafka 和 Kinesis connector 的元數據,并且 FileSystem connector 上的相關工作也已經在計劃中(FLINK-19903)。由于 Kafka record 的結構比較復雜,社區還專門為 Kafka connector 實現了新的屬性[8],以控制如何處理鍵/值對。關于 Flink SQL 中元數據支持的完整描述,請查看每個 connector 的文檔[9]以及 FLIP-107 中描述的用例。

Table API/SQL: Upsert Kafka Connector

在某些場景中,例如讀取 compacted topic 或者輸出(更新)聚合結果的時候,需要將 Kafka 消息記錄的 key 當成主鍵處理,用來確定一條數據是應該作為插入、刪除還是更新記錄來處理。為了實現該功能,社區為 Kafka 專門新增了一個 upsert connector(upsert-kafka),該 connector 擴展自現有的 Kafka connector,工作在 upsert 模式(FLIP-149)下。新的 upsert-kafka connector 既可以作為 source 使用,也可以作為 sink 使用,并且提供了與現有的 kafka connector 相同的基本功能和持久性保證,因為兩者之間復用了大部分代碼。

要使用 upsert-kafka connector,必須在創建表時定義主鍵,并為鍵(key.format)和值(value.format)指定序列化反序列化格式。完整的示例,請查看最新的文檔[10]。

Table API/SQL: SQL 中 支持 Temporal Table Join

在之前的版本中,用戶需要通過創建時態表函數(temporal table function) 來支持時態表 join(temporal table join) ,而在 Flink 1.12 中,用戶可以使用標準的 SQL 語句 FOR SYSTEM_TIME AS OF(SQL:2011)來支持 join。此外,現在任意包含時間列和主鍵的表,都可以作為時態表,而不僅僅是 append-only 表。這帶來了一些新的應用場景,比如將 Kafka compacted topic 或數據庫變更日志(來自 Debezium 等)作為時態表。

CREATE TABLE orders (
    order_id STRING,
    currency STRING,
    amount INT,              
    order_time TIMESTAMP(3),                
    WATERMARK FOR order_time AS order_time - INTERVAL '30' SECOND
) WITH (
  …
);

-- Table backed by a Kafka compacted topic
CREATE TABLE latest_rates ( 
    currency STRING,
    rate DECIMAL(38, 10),
    currency_time TIMESTAMP(3),
    WATERMARK FOR currency_time AS currency_time - INTERVAL ‘5’ SECOND,
    PRIMARY KEY (currency) NOT ENFORCED      
) WITH (
  'connector' = 'upsert-kafka',
  …
);

-- Event-time temporal table join
SELECT 
  o.order_id,
  o.order_time,
  o.amount * r.rate AS amount,
  r.currency
FROM orders AS o, latest_rates FOR SYSTEM_TIME AS OF o.order_time r
ON o.currency = r.currency;

上面的示例同時也展示了如何在 temporal table join 中使用 Flink 1.12 中新增的 upsert-kafka connector。

■ 使用 Hive 表進行 Temporal Table Join

用戶也可以將 Hive 表作為時態表來使用,Flink 既支持自動讀取 Hive 表的最新分區作為時態表(FLINK-19644),也支持在作業執行時追蹤整個 Hive 表的最新版本作為時態表。請參閱文檔,了解更多關于如何在 temporal table join 中使用 Hive 表的示例。

Table API/SQL 中的其它改進

**■ Kinesis Flink SQL Connector (FLINK-18858)
**
從 Flink 1.12 開始,Table API / SQL 原生支持將 Amazon Kinesis Data Streams(KDS)作為 source 和 sink 使用。新的 Kinesis SQL connector 提供了對于增強的Fan-Out(EFO)以及 Sink Partition 的支持。如需了解 Kinesis SQL connector 所有支持的功能、配置選項以及對外暴露的元數據信息,請查看最新的文檔。

**■ 在 FileSystem/Hive connector 的流式寫入中支持小文件合并 (FLINK-19345)
**
很多 bulk format,例如 Parquet,只有當寫入的文件比較大時,才比較高效。當 checkpoint 的間隔比較小時,這會成為一個很大的問題,因為會創建大量的小文件。在 Flink 1.12 中,File Sink 增加了小文件合并功能,從而使得即使作業 checkpoint 間隔比較小時,也不會產生大量的文件。要開啟小文件合并,可以按照文檔[11]中的說明在 FileSystem connector 中設置 auto-compaction = true 屬性。

■ Kafka Connector 支持 Watermark 下推 (FLINK-20041)

為了確保使用 Kafka 的作業的結果的正確性,通常來說,最好基于分區來生成 watermark,因為分區內數據的亂序程度通常來說比分區之間數據的亂序程度要低很多。Flink 現在允許將 watermark 策略下推到 Kafka connector 里面,從而支持在 Kafka connector 內部構造基于分區的 watermark[12]。一個 Kafka source 節點最終所產生的 watermark 由該節點所讀取的所有分區中的 watermark 的最小值決定,從而使整個系統可以獲得更好的(即更接近真實情況)的 watermark。該功能也允許用戶配置基于分區的空閑檢測策略,以防止空閑分區阻礙整個作業的 event time 增長。

■ 新增的 Formats

3.png

■ 利用 Multi-input 算子進行 Join 優化 (FLINK-19621)

Shuffling 是一個 Flink 作業中最耗時的操作之一。為了消除不必要的序列化反序列化開銷、數據 spilling 開銷,提升 Table API / SQL 上批作業和流作業的性能, planner 當前會利用上一個版本中已經引入的N元算子(FLIP-92),將由 forward 邊所連接的多個算子合并到一個 Task 里執行。

■ Type Inference for Table API UDAFs (FLIP-65)

Flink 1.12 完成了從 Flink 1.9 開始的,針對 Table API 上的新的類型系統[2]的工作,并在聚合函數(UDAF)上支持了新的類型系統。從 Flink 1.12 開始,與標量函數和表函數類似,聚合函數也支持了所有的數據類型。

PyFlink: Python DataStream API

為了擴展 PyFlink 的可用性,Flink 1.12 提供了對于 Python DataStream API(FLIP-130)的初步支持,該版本支持了無狀態類型的操作(例如 Map,FlatMap,Filter,KeyBy 等)。如果需要嘗試 Python DataStream API,可以安裝PyFlink,然后按照該文檔[14]進行操作,文檔中描述了如何使用 Python DataStream API 構建一個簡單的流應用程序。

from pyflink.common.typeinfo import Types
from pyflink.datastream import MapFunction, StreamExecutionEnvironment
class MyMapFunction(MapFunction):
    def map(self, value):
        return value + 1
env = StreamExecutionEnvironment.get_execution_environment()
data_stream = env.from_collection([1, 2, 3, 4, 5], type_info=Types.INT())
mapped_stream = data_stream.map(MyMapFunction(), output_type=Types.INT())
mapped_stream.print()
env.execute("datastream job")

PyFlink 中的其它改進

**■ PyFlink Jobs on Kubernetes (FLINK-17480)
**
除了 standalone 部署和 YARN 部署之外,現在也原生支持將 PyFlink 作業部署在 Kubernetes 上。最新的文檔中詳細描述了如何在 Kubernetes 上啟動 session 或 application 集群。

**■ 用戶自定義聚合函數 (UDAFs)
**
從 Flink 1.12 開始,您可以在 PyFlink 作業中定義和使用 Python UDAF 了(FLIP-139)。普通的 UDF(標量函數)每次只能處理一行數據,而 UDAF(聚合函數)則可以處理多行數據,用于計算多行數據的聚合值。您也可以使用 Pandas UDAF[15](FLIP-137),來進行向量化計算(通常來說,比普通 Python UDAF 快10倍以上)。

注意: 普通 Python UDAF,當前僅支持在 group aggregations 以及流模式下使用。如果需要在批模式或者窗口聚合中使用,建議使用 Pandas UDAF。

五. Flink 1.13 新特性

  1. flink1.13新特性,該部分內容轉自 官宣|Apache Flink 1.13.0 正式發布,流處理應用更加簡單高效!
    發布時間:2021.5.3

1. 被動擴縮容

Flink 項目的一個初始目標,就是希望流處理應用可以像普通應用一樣簡單和自然,被動擴縮容是 Flink 針對這一目標上的最新進展。

當考慮資源管理和部分的時候,Flink 有兩種可能的模式。用戶可以將 Flink 應用部署到 k8s、yarn 等資源管理系統之上,并且由 Flink 主動的來管理資源并按需分配和釋放資源。這一模式對于經常改變資源需求的作業和應用非常有用,比如批作業和實時 SQL 查詢。在這種模式下,Flink 所啟動的 Worker 數量是由應用設置的并發度決定的。在 Flink 中我們將這一模式叫做主動擴縮容。

對于長時間運行的流處理應用,一種更適合的模型是用戶只需要將作業像其它的長期運行的服務一樣啟動起來,而不需要考慮是部署在 k8s、yarn 還是其它的資源管理平臺上,并且不需要考慮需要申請的資源的數量。相反,它的規模是由所分配的 worker 數量來決定的。當 worker 數量發生變化時,Flink 自動的改動應用的并發度。在 Flink 中我們將這一模式叫做被動擴縮容。

Flink 的 Application 部署模式開啟了使 Flink 作業更接近普通應用(即啟動 Flink 作業不需要執行兩個獨立的步驟來啟動集群和提交應用)的努力,而被動擴縮容完成了這一目標:用戶不再需要使用額外的工具(如腳本、K8s 算子)來讓 worker 的數量與應用并發度設置保持一致。

用戶現在可以將自動擴縮容的工具應用到 Flink 應用之上,就像普通的應用程序一樣,只要用戶了解擴縮容的代價:有狀態的流應用在擴縮容的時候需要將狀態重新分發。

如果想要嘗試被動擴縮容,用戶可以增加 scheduler-mode: reactive 這一配置項,然后啟動一個應用集群(Standalone 或者 K8s)。更多細節見被動擴縮容的文檔

2. 分析應用的性能

對所有應用程序來說,能夠簡單的分析和理解應用的性能是非常關鍵的功能。這一功能對 Flink 更加重要,因為 Flink 應用一般是數據密集的(即需要處理大量的數據)并且需要在(近)實時的延遲內給出結果。

當 Flink 應用處理的速度跟不上數據輸入的速度時,或者當一個應用占用的資源超過預期,下文介紹的這些工具可以幫你分析原因。

2.1 瓶頸檢測與反壓監控

Flink 性能分析首先要解決的問題經常是:哪個算子是瓶頸?

為了回答這一問題,Flink 引入了描述作業繁忙(即在處理數據)與反壓(由于下游算子不能及時處理結果而無法繼續輸出)程度的指標。應用中可能的瓶頸是那些繁忙并且上游被反壓的算子。

Flink 1.13 優化了反壓檢測的邏輯(使用基于任務 Mailbox 計時,而不在再于堆棧采樣),并且重新實現了作業圖的 UI 展示:Flink 現在在 UI 上通過顏色和數值來展示繁忙和反壓的程度。

null

2.2 Web UI 中的 CPU 火焰圖

Flink 關于性能另一個經常需要回答的問題:瓶頸算子中的哪部分計算邏輯消耗巨大?

針對這一問題,一個有效的可視化工具是火焰圖。它可以幫助回答以下問題:

  • 哪個方法調現在在占用 CPU?
  • 不同方法占用 CPU 的比例如何?
  • 一個方法被調用的棧是什么樣子的?

火焰圖是通過重復采樣線程的堆棧來構建的。在火焰圖中,每個方法調用被表示為一個矩形,矩形的長度與這個方法出現在采樣中的次數成正比。火焰圖在 UI 上的一個例子如下圖所示。

null

火焰圖的文檔 包括啟用這一功能的更多細節和指令。

2.3 State 訪問延遲指標

另一個可能的性能瓶頸是 state backend,尤其是當作業的 state 超過內存容量而必須使用 RocksDB state backend 時。

這里并不是想說 RocksDB 性能不夠好(我們非常喜歡 RocksDB!),但是它需要滿足一些條件才能達到最好的性能。例如,用戶可能很容易遇到非故意的在云上由于使用了錯誤的磁盤資源類型而不能滿足 RockDB 的 IO 性能需求的問題。

基于 CPU 火焰圖,新的 State Backend 的延遲指標可以幫助用戶更好的判斷性能不符合預期是否是由 State Backend 導致的。例如,如果用戶發現 RocksDB 的單次訪問需要幾毫秒的時間,那么就需要查看內存和 I/O 的配置。這些指標可以通過設置 state.backend.rocksdb.latency-track-enabled 這一選項來啟用。這些指標是通過采樣的方式來監控性能的,所以它們對 RocksDB State Backend 的性能影響是微不足道的。

3. 通過 Savepoint 來切換 State Backend

用戶現在可以在從一個 Savepoint 重啟時切換一個 Flink 應用的 State Backend。這使得 Flink 應用不再被限制只能使用應用首次運行時選擇的 State Backend。

基于這一功能,用戶現在可以首先使用一個 HashMap State Backend(純內存的 State Backend),如果后續狀態變得過大的話,就切換到 RocksDB State Backend 中。

在實現層,Flink 現在統一了所有 State Backend 的 Savepoint 格式來實現這一功能。

4. K8s 部署時使用用戶指定的 Pod 模式

原生 kubernetes 部署(Flink 主動要求 K8s 來啟動 Pod)中,現在可以使用自定義的 Pod 模板。

使用這些模板,用戶可以使用一種更符合 K8s 的方式來設置 JM 和 TM 的 Pod,這種方式比 Flink K8s 集成內置的配置項更加靈活。

5. 生產可用的 Unaligned Checkpoint

Unaligned Checkpoint 目前已達到了生產可用的狀態,我們鼓勵用戶在存在反壓的情況下試用這一功能。

具體來說,Flink 1.13 中引入的這些功能使 Unaligned Checkpoint 更容易使用:

  • 用戶現在使用 Unaligned Checkpoint 時也可以擴縮容應用。如果用戶需要因為性能原因不能使用 Savepoint而必須使用 Retained checkpoint 時,這一功能會非常方便。
  • 對于沒有反壓的應用,啟用 Unaligned Checkpoint 現在代價更小。Unaligned Checkpoint 現在可以通過超時來自動觸發,即一個應用默認會使用 Aligned Checkpoint(不存儲傳輸中的數據),而只在對齊超過一定時間范圍時自動切換到 Unaligned Checkpoint(存儲傳輸中的數據)。

關于如何啟用 Unaligned Checkpoint 可以參考相關文檔

6. 機器學習遷移到單獨的倉庫

為了加速 Flink 機器學習的進展(流批統一的機器學習),現在 Flink 機器學習開啟了新的 flink-ml 倉庫。我們采用類似于 Stateful Function 項目的管理方式,通過使用一個單獨的倉庫從而簡化代碼合并的流程并且可以進行單獨的版本發布,從而提高開發的效率。

用戶可以關注 Flink 在機器學習方面的進展,比如與 Alink(Flink 常用機器學習算法套件)的互操作以及 Flink 與 Tensorflow 的集成

二、SQL / Table API 進展

與之前的版本類似,SQL 和 Table API 仍然在所有開發中占用很大的比例。

1. 通過 Table-valued 函數來定義時間窗口

在流式 SQL 查詢中,一個最經常使用的是定義時間窗口。Flink 1.13 中引入了一種新的定義窗口的方式:通過 Table-valued 函數。這一方式不僅有更強的表達能力(允許用戶定義新的窗口類型),并且與 SQL 標準更加一致。

Flink 1.13 在新的語法中支持 TUMBLE 和 HOP 窗口,在后續版本中也會支持 SESSION 窗口。我們通過以下兩個例子來展示這一方法的表達能力:

  • 例 1:一個新引入的 CUMULATE 窗口函數,它可以支持按特定步長擴展的窗口,直到達到最大窗口大小:
SELECT window_time, window_start, window_end, SUM(price) AS total_price 
  FROM TABLE(CUMULATE(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '2' MINUTES, INTERVAL '10' MINUTES))
GROUP BY window_start, window_end, window_time;
  • 例 2:用戶在 table-valued 窗口函數中可以訪問窗口的起始和終止時間,從而使用戶可以實現新的功能。例如,除了常規的基于窗口的聚合和 Join 之外,用戶現在也可以實現基于窗口的 Top-K 聚合:
SELECT window_time, ...
  FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY window_start, window_end ORDER BY total_price DESC) 
      as rank 
    FROM t
  ) WHERE rank <= 100; 

2. 提高 DataStream API 與 Table API / SQL 的互操作能力

這一版本極大的簡化了 DataStream API 與 Table API 混合的程序。

Table API 是一種非常方便的應用開發接口,因為這經支持表達式的程序編寫并提供了大量的內置函數。但是有時候用戶也需要切換回 DataStream,例如當用戶存在表達能力、靈活性或者 State 訪問的需求時。

Flink 新引入的 StreamTableEnvironment.toDataStream()/.fromDataStream() 可以將一個 DataStream API 聲明的 Source 或者 Sink 當作 Table 的 Source 或者 Sink 來使用。主要的優化包括:

  • DataStream 與 Table API 類型系統的自動轉換。
  • Event Time 配置的無縫集成,Watermark 行為的高度一致性。
  • Row 類型(即 Table API 中數據的表示)有了極大的增強,包括 toString() / hashCode() 和 equals() 方法的優化,按名稱訪問字段值的支持與稀疏表示的支持。
Table table = tableEnv.fromDataStream(
  dataStream,
  Schema.newBuilder()
    .columnByMetadata("rowtime", "TIMESTAMP(3)")
    .watermark("rowtime", "SOURCE_WATERMARK()")
    .build());

DataStream<Row> dataStream = tableEnv.toDataStream(table)
  .keyBy(r -> r.getField("user"))
  .window(...);

3. SQL Client: 初始化腳本和語句集合 (Statement Sets)

SQL Client 是一種直接運行和部署 SQL 流或批作業的簡便方式,用戶不需要編寫代碼就可以從命令行調用 SQL,或者作為 CI / CD 流程的一部分。

這個版本極大的提高了 SQL Client 的功能。現在基于所有通過 Java 編程(即通過編程的方式調用 TableEnvironment 來發起查詢)可以支持的語法,現在 SQL Client 和 SQL 腳本都可以支持。這意味著 SQL 用戶不再需要添加膠水代碼來部署他們的SQL作業。

3.1 配置簡化和代碼共享

Flink 后續將不再支持通過 Yaml 的方式來配置 SQL Client(注:目前還在支持,但是已經被標記為廢棄)。作為替代,SQL Client 現在支持使用一個初始化腳本在主 SQL 腳本執行前來配置環境。

這些初始化腳本通常可以在不同團隊/部署之間共享。它可以用來加載常用的 catalog,應用通用的配置或者定義標準的視圖。

./sql-client.sh -i init1.sql init2.sql -f sqljob.sql

3.2 更多的配置項

通過增加配置項,優化 SET / RESET 命令,用戶可以更方便的在 SQL Client 和 SQL 腳本內部來控制執行的流程。

3.3 通過語句集合來支持多查詢

多查詢允許用戶在一個 Flink 作業中執行多個 SQL 查詢(或者語句)。這對于長期運行的流式 SQL 查詢非常有用。

語句集可以用來將一組查詢合并為一組同時執行。

以下是一個可以通過 SQL Client 來執行的 SQL 腳本的例子。它初始化和配置了執行多查詢的環境。這一腳本包括了所有的查詢和所有的環境初始化和配置的工作,從而使它可以作為一個自包含的部署組件。

-- set up a catalog
CREATE CATALOG hive_catalog WITH ('type' = 'hive');
USE CATALOG hive_catalog;

-- or use temporary objects
CREATE TEMPORARY TABLE clicks (
  user_id BIGINT,
  page_id BIGINT,
  viewtime TIMESTAMP
) WITH (
  'connector' = 'kafka',
  'topic' = 'clicks',
  'properties.bootstrap.servers' = '...',
  'format' = 'avro'
);

-- set the execution mode for jobs
SET execution.runtime-mode=streaming;

-- set the sync/async mode for INSERT INTOs
SET table.dml-sync=false;

-- set the job's parallelism
SET parallism.default=10;

-- set the job name
SET pipeline.name = my_flink_job;

-- restore state from the specific savepoint path
SET execution.savepoint.path=/tmp/flink-savepoints/savepoint-bb0dab;

BEGIN STATEMENT SET;

INSERT INTO pageview_pv_sink
SELECT page_id, count(1) FROM clicks GROUP BY page_id;

INSERT INTO pageview_uv_sink
SELECT page_id, count(distinct user_id) FROM clicks GROUP BY page_id;

END;

4. Hive 查詢語法兼容性

用戶現在在 Flink 上也可以使用 Hive SQL 語法。除了 Hive DDL 方言之外,Flink現在也支持常用的 Hive DML 和 DQL 方言。

為了使用 Hive SQL 方言,需要設置 table.sql-dialect 為 hive 并且加載 HiveModule。后者非常重要,因為必須要加載 Hive 的內置函數后才能正確實現對 Hive 語法和語義的兼容性。例子如下:

CREATE CATALOG myhive WITH ('type' = 'hive'); -- setup HiveCatalog
USE CATALOG myhive;
LOAD MODULE hive; -- setup HiveModule
USE MODULES hive,core;
SET table.sql-dialect = hive; -- enable Hive dialect
SELECT key, value FROM src CLUSTER BY key; -- run some Hive queries 

需要注意的是, Hive 方言中不再支持 Flink 語法的 DML 和 DQL 語句。如果要使用 Flink 語法,需要切換回 default 的方言配置。

5. 優化的 SQL 時間函數

在數據處理中時間處理是一個重要的任務。但是與此同時,處理不同的時區、日期和時間是一個日益復雜的任務。

在 Flink 1.13 中,我們投入了大量的精力來簡化時間函數的使用。我們調整了時間相關函數的返回類型使其更加精確,例如 PROCTIME(),CURRENT_TIMESTAMP() 和 NOW()。

其次,用戶現在還可以基于一個 TIMESTAMP_LTZ 類型的列來定義 Event Time 屬性,從而可以優雅的在窗口處理中支持夏令時。

用戶可以參考 Release Note 來查看該部分的完整變更。

三、PyFlink 核心優化

這個版本對 PyFlink 的改進主要是使基于 Python 的 DataStream API 與 Table API 與 Java/scala 版本的對應功能更加一致。

1. Python DataStream API 中的有狀態算子

在 Flink 1.13 中,Python 程序員可以享受到 Flink 狀態處理 API 的所有能力。在 Flink 1.12 版本重構過的 Python DataStream API 現在已經擁有完整的狀態訪問能力,從而使用戶可以將數據的信息記錄到 state 中并且在后續訪問。

帶狀態的處理能力是許多依賴跨記錄狀態共享(例如 Window Operator)的復雜數據處理場景的基礎。

以下例子展示了一個自定義的計算窗口的實現:

class CountWindowAverage(FlatMapFunction):
    def __init__(self, window_size):
        self.window_size = window_size

    def open(self, runtime_context: RuntimeContext):
        descriptor = ValueStateDescriptor("average", Types.TUPLE([Types.LONG(), Types.LONG()]))
        self.sum = runtime_context.get_state(descriptor)

    def flat_map(self, value):
        current_sum = self.sum.value()
        if current_sum is None:
            current_sum = (0, 0)
        # update the count
        current_sum = (current_sum[0] + 1, current_sum[1] + value[1])
        # if the count reaches window_size, emit the average and clear the state
        if current_sum[0] >= self.window_size:
            self.sum.clear()
            yield value[0], current_sum[1] // current_sum[0]
        else:
            self.sum.update(current_sum)

ds = ...  # type: DataStream
ds.key_by(lambda row: row[0]) \
  .flat_map(CountWindowAverage(5))

2. PyFlink DataStream API 中的用戶自定義窗口

Flink 1.13 中 PyFlink DataStream 接口增加了對用戶自定義窗口的支持,現在用戶可以使用標準窗口之外的窗口定義。

由于窗口是處理無限數據流的核心機制 (通過將流切分為多個有限的『桶』),這一功能極大的提高的 API 的表達能力。

3. PyFlink Table API 中基于行的操作

Python Table API 現在支持基于行的操作,例如用戶對行數據的自定義函數。這一功能使得用戶可以使用非內置的數據處理函數。

一個使用 map() 操作的 Python Table API 示例如下:

@udf(result_type=DataTypes.ROW(
  [DataTypes.FIELD("c1", DataTypes.BIGINT()),
   DataTypes.FIELD("c2", DataTypes.STRING())]))
def increment_column(r: Row) -> Row:
  return Row(r[0] + 1, r[1])

table = ...  # type: Table
mapped_result = table.map(increment_column)

除了 map(),這一 API 還支持 flat_map(),aggregate(),flat_aggregate() 和其它基于行的操作。這使 Python Table API 的功能與 Java Table API 的功能更加接近。

4. PyFlink DataStream API 支持 Batch 執行模式

對于有限流,PyFlink DataStream API 現在已經支持 Flink 1.12 DataStream API 中引入的 Batch 執行模式。

通過復用數據有限性來跳過 State backend 和 Checkpoint 的處理,Batch 執行模式可以簡化運維,并且提高有限流處理的性能。

四、其它優化

1. 基于 Hugo 的 Flink 文檔

Flink 文檔從 JekyII 遷移到了 Hugo。如果您發現有問題,請務必通知我們,我們非常期待用戶對新的界面的感受。

2. Web UI 支持歷史異常

Flink Web UI 現在可以展示導致作業失敗的 n 次歷史異常,從而提升在一個異常導致多個后續異常的場景下的調試體驗。用戶可以在異常歷史中找到根異常。

3. 優化失敗 Checkpoint 的異常和失敗原因的匯報

Flink 現在提供了失敗或被取消的 Checkpoint 的統計,從而使用戶可以更簡單的判斷 Checkpoint 失敗的原因,而不需要去查看日志。

Flink 之前的版本只有在 Checkpoint 成功的時候才會匯報指標(例如持久化數據的大小、觸發時間等)。

4. 提供『恰好一次』一致性的 JDBC Sink

從 1.13 開始,通過使用事務提交數據,JDBC Sink 可以對支持 XA 事務的數據庫提供『恰好一次』的一致性支持。這一特性要求目標數據庫必須有(或鏈接到)一個 XA 事務處理器。

這一 Sink 現在只能在 DataStream API 中使用。用戶可以通過 JdbcSink.exactlyOnceSink(…) 來創建這一 Sink(或者通過顯式初始化一個 JdbcXaSinkFunction)。

5. PyFlink Table API 在 Group 窗口上支持用戶自定義的聚合函數

PyFlink Table API 現在對 Group 窗口同時支持基于 Python 的用戶自定義聚合函數(User-defined Aggregate Functions, UDAFs)以及 Pandas UDAFs。這些函數對許多數據分析或機器學習訓練的程序非常重要。

在 Flink 1.13 之前,這些函數僅能在無限的 Group-by 聚合場景下使用。Flink 1.13 優化了這一限制。

6. Batch 執行模式下 Sort-merge Shuffle 優化

Flink 1.13 優化了針對批處理程序的 Sort-merge Blocking Shuffle 的性能和內存占用情況。這一 Shuffle 模式是在Flink 1.12 的 FLIP-148 中引入的。

這一優化避免了大規模作業下不斷出現 OutOfMemoryError: Direct Memory 的問題,并且通過 I/O 調度和 broadcast 優化提高了性能(尤其是在機械硬盤上)。

7. HBase 連接器支持異步維表查詢和查詢緩存

HBase Lookup Table Source 現在可以支持異步查詢模式和查詢緩存。這極大的提高了使用這一 Source 的 Table / SQL 維表 Join 的性能,并且在一些典型情況下可以減少對 HBase 的 I/O 請求數量。

在之前的版本中,HBase Lookup Source 僅支持同步通信,從而導致作業吞吐以及資源利用率降低。

8. 升級 Flink 1.13 需要注意的改動

  • FLINK-21709 – 老的 Table & SQL API 計劃器已經被標記為廢棄,并且將在 Flink 1.14 中被刪除。Blink 計劃器在若干版本之前已經被設置為默認計劃器,并且將成為未來版本中的唯一計劃器。這意味著 BatchTableEnvironment 和 DataSet API 互操作后續也將不再支持。用戶需要切換到統一的 TableEnvironment 來編寫流或者批的作業。
  • FLINK-22352 – Flink 社區決定廢棄對 Apache mesos 的支持,未來有可能會進一步刪除這部分功能。用戶最好能夠切換到其它的資源管理系統上。
  • FLINK-21935 – state.backend.async 這一配置已經被禁用了,因為現在 Flink 總是會異步的來保存快照(即之前的配置默認值),并且現在沒有實現可以支持同步的快照保存操作。
  • FLINK-17012 – Task 的 RUNNING 狀態被細分為兩步:INITIALIZING 和 RUNNING。Task 的 INITIALIZING 階段包括加載 state 和在啟用 unaligned checkpoint 時恢復 In-flight 數據的過程。通過顯式區分這兩種狀態,監控系統可以更好的區分任務是否已經在實際工作。
  • FLINK-21698 – NUMERIC 和 TIMESTAMP 類型之間的直接轉換存在問題,現在已經被禁用,例如 CAST(numeric AS TIMESTAMP(3))。用戶應該使用 TO_TIMESTAMP(FROM_UNIXTIME(numeric)) 來代替。
  • FLINK-22133 – 新的 Source 接口有一個小的不兼容的修改,即 SplitEnumerator.snapshotState() 方法現在多接受一個 checkpoint id 參數來表示正在進行的 snapshot 操作所屬的 checkpoint 的 id。
  • FLINK-19463 – 由于老的 Statebackend 接口承載了過多的語義并且容易引起困惑,這一接口被標記為廢棄。這是一個純 API 層的改動,而并不會影響應用運行時。對于如何升級現有作業,請參考 作業遷移指引
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內容

  • 本文僅為筆者平日學習記錄之用,侵刪原文:https://mp.weixin.qq.com/s/kX3ZmJARRW...
    longLiveData閱讀 2,492評論 0 1
  • 表情是什么,我認為表情就是表現出來的情緒。表情可以傳達很多信息。高興了當然就笑了,難過就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 125,537評論 2 7
  • 16宿命:用概率思維提高你的勝算 以前的我是風險厭惡者,不喜歡去冒險,但是人生放棄了冒險,也就放棄了無數的可能。 ...
    yichen大刀閱讀 6,076評論 0 4