摘要:本文整理自阿里巴巴開發工程師羅宇俠&方盛凱,在 Flink Forward Asia 2022 流批一體專場的分享。本篇內容主要分為五個部分:
- 構建流批一體引擎的挑戰
- Hive SQL on Flink
- 流批一體引擎的收益
- Demo
- 未來展望
一、構建流批一體引擎的挑戰
目前,流和批仍然是相對割裂的。雖然我們在應用層統一了,但從接入層開始,不同的引擎依舊有不同的接入層、API 層、執行層。我們認為,統一的流批一體引擎應該是從接入層開始使用 SQL Gateway 作為接入層。在 API 層使用 Flink SQL 作為編寫作業的主要語言,在執行層替換成統一的 Runtime。
為了達成統一的流體引擎,我們認為有以下兩個難點:
- 應用層的對接。在流批割裂的環境下,應用層仍然是有不同的提交平臺,如何保證原來的應用層能無損且直接地對接到新的 SQL Gateway 上,是一個巨大的難點。
- 使用者作業遷移的成本。使用者原來的 Batch 作業是用 Hive SQL 進行撰寫的,現在則需要替換成 Flink SQL。為了保證使用者的作業能無損遷上來,我們需要解決語言上的相容和使用者所用的 UDF 的相容。
為此我們圍繞以下兩點在 Flink 1.16 上做了大量改進,保證了 Hive SQL on Flink 構建流批一體引擎是可行的。
- Flink 對 Hive SQL 的相容,我們在 1.16 中大大提升了對 Hive SQL 本身的相容性。
- 我們在 Flink 社群引入了 SQL Gateway,從而相容 Hive 的生態。
二、Hive SQL on Flink
接下來我來講一下 Flink 社群具體做的一些工作來使得基於 Hive SQL on Flink 構建流批一體引擎成為可能。
在這一方面,Flink 社群經過多個版本的打磨,做了大量的工作使得基於 Hive SQL on Flink 構建流批一體引擎能夠在生產中可用。
2.1 Hive SQL on Flink 的具體工作
第一,整合 Hive MetaStore。眾所周知,在大資料領域,Hive MetaStore 已經是事實的後設資料管理標準了,所以 Flink 在很早的版本就已經開始整合 Hive MetaStore。主要分為以下三方面的支援:
- 支援 Hive MetaStore 作為 Flink 的 Catalog,Hive 已有的表可自動註冊進 Flink 中,使用者無需再定義各種 DDL 來對映底層的 Hive 表。
- 支援 Hive MetaStore 儲存 Flink 定義的 Hive 表/ 非 Hive 表。
- 支援從 Hive MetaStore 獲得表的統計資訊,從而最佳化查詢的執行計劃,提升端到端 SQL 的效能。
第二,整合 Hive 的 UDF。主要支援以下兩方面:
- Hive 提供了非常豐富的 UDF,在 Flink 中我們可以直接呼叫 Hive 中內建的 UDF。換句話說,使用者使用 Flink 就能享受到 Hive 那套內建 UDF 所帶來的方便及易用性。
- 支援呼叫自定義的 Hive UDF。對於熟悉 Hive 的人,他們會基於 Hive UDF 的介面去定義自己的 UDF。但如果他們想用 Flink,又不想廢棄那些 UDF,更不想重寫。要怎麼辦呢?其實 Flink 支援呼叫使用者自定義的 Hive UDF,所以使用者不需要對 UDF 做任何重寫的工作,這極大的方便了使用者的操作。
第三,Hive 表的讀寫。主要支援以下幾方面:
- 支援流讀/批讀/流寫/批寫 Hive 表。
- 批讀 Hive 表支援靜態分割槽裁剪和動態分割槽裁剪。可以大幅削減讀取資料的規模,從而提升讀的效能和效率。
- 批讀 Hive 表支援併發推斷。在批場景下,併發設定是一個比較難的問題,但如果在批讀 Hive 場景下,我們可以透過 Hive 表的檔案資訊推斷出合理的併發,從而提升端到端鏈路的效能。
- 批寫/流寫 Hive 支援自定義分割槽提交策略。在批排程鏈路裡,我們可能會把先提交分割槽,然後觸發一些其他下游的操作或排程,這時我們無需引入其他額外的元件,直接在 Flink 裡自定義這些分割槽提交的策略即可。比如指定分割槽提交後,觸發定時任務或者在訊息佇列插一條資料等等。
- 流寫 Hive 表支援小檔案自動合併。在流的場景下,會生成很多小檔案,但在流寫 Hive 表時,我們支援小檔案的自動合併,透過將小檔案合併成更大的檔案,減少了小檔案的數量,從而緩解 HDFS 叢集的壓力。
- 批寫 Hive 表支援自動收集統計資訊,這一部分完全相容了 Hive 的行為。在使用 Hive 寫 Hive 表的時候,它會收集統計資訊並提交到 MetaStore。我們用 Flink 寫 Hive 表的時候,也能支援將統計資訊提交到 MetaStore,包括檔案的大小、資料的條數等等。
2.2 Flink 相容 Hive SQL 的架構
使用者的 Hive SQL 如何在 Flink 中順滑地執行?上圖是 Flink 相容 Hive SQL 的架構,可以看到,它被分成了兩個不同的分支,Flink SQL 和 Hive SQL。然後它們會由不同的 Parser 去做解析,Flink SQL 透過 Flink Parser 做解析,Hive SQL 透過 Hive Parser 做解析,Hive Parser 的行為和 Hive 的行為保持一致。
接下來它們都會生成 Flink 裡的 Logical Plan,Logical Plan 進行最佳化,生成 Physical Plan,Physical Plan 再進行翻譯,生成具體的 Job Graph,最後交由 Flink Runtime 執行。
基於這套架構,我們可以很方便地擴充套件 Flink 來提供對其他語法的支援。另外透過這套架構,我們理論上還能達到對 Hive 語法的百分之百相容。
2.3 Flink 對 Hive SQL 的相容
接下來講一下我們最後達到了怎樣的效果。
第一,支援生產上常用的 Hive 語法。即生產上的作業能夠很好地遷移到我們的 Flink 中執行。主要支援以下語法:
- 支援 distribute by/sort by/ cluster by。
- 支援 multi insert。一個 scan 可以插入到多個不同資料的 sink 端,極大的提高了資料 ETL 鏈路的效率。
- 支援 insert directory。
- 支援 load data。
- 支援 create function using jar。
- ……
那麼我們到底對 Hive SQL 的相容度能達到多少呢?答案是 94%了。這個數字又是怎麼得出來的呢?
- 基於 Hive 2.3 的 qtest 測試集,12000 條 DQL/DML 都扔到 Flink 去執行,這些 SQL 都能夠被正常執行。
- 12000 條 DQL/DML 也包含了很多對 ACID 表的查詢。Hive 的 ACID 表在生產中用的較少,如果我們除去針對 ACID 表的 DQL/DML,相容度可達 97%。
2.4 Flink 對 Hive 生態的相容
如上圖所示,之前的內容講的是 API 層、執行層已經統一了。 那麼我們如何在接入層也把它統一掉呢?就引出我們接下來要分享的 Flink SQL Gateway 了。
2.5 引入 Flink SQL Gateway 的原因
我們為什麼引入 Flink SQL Gateway 呢?原因有以下三個:
- 目前 Flink 社群官方提供了 SQL Client 供使用者提交 SQL 作業。但由於 SQL Client 本身沒有服務化,使用者往往需要基於 SQL Client 做一層封裝,新增一個服務化的前端。透過該服務化的前端,使用者的 SQL 作業最終會被提交給 SQL Client 去執行。以上的過程比較繁瑣而且開發成本較大,因此,我們在社群提供了一個預設的服務化的實現,降低使用者的使用成本。
- 以上的方案是基於 SQL Client 來做的作業提交,但這套 API 並不穩定。而引入的 SQL Gateway 則提供了穩定的 API。
- 相比於 SQL Client, SQL Gateway 是 C/S 架構,更容易對接諸多生態 ,e.g. HiveServer2。
基於以上的考量,Flink 社群引入了 Flink SQL Gateway。它有以下特點:
- 開箱即用,使用者可以直接使用 SQL Gateway 搭建一個生產可用的提交工具。
- 生態對接,提供了穩定的 API,方便 Flink 對接其它生態工具。
- 相容 HiveServer2 協議,提供了 HiveServer2 Endpoint 以相容 Hive 生態。
2.6 Flink SQL Gateway 架構
上圖是 Flink SQL Gateway 的架構圖,可以分成前端和後端。
後端提供了多租戶能力,可以對接不同的叢集,包括 Flink Standalone,Flink On Yarn 等。另外,它支援使用者自定義的 Catalog,可以用預設的 Catalog,也可以用 MySQL Catalog、Hive Catalog。
SQL Gateway 目前提供了兩個 Endpoint,分別是 REST Endpoint 和 HiveServer2 Endpoint。
- REST Endpoint:使用者可以透過 REST 工具提交作業。
- HiveServer2 Endpoint:透過它我們就能提供對接 Hive 主流生態的能力。
從上圖左側可以看到目前一些 Hive 的生態工具,包括 Beeline、DBeaver、DolphinScheduler、Superset、Apache Zeppelin 等,都能很好的對接到 Flink SQL Gateway 上。
2.7 HiveServer2 Endpoint
上面提到 HiveServer2 Endpoint 在相容 Hive 生態的重要性,接下來讓我們一起來看一下它的具體架構。從上圖可以看到主要分為兩層,Client 端和 Server 端。HiveServer2 實際上是定義了 Client 端和 Server 端的一套通訊協議,如果要相容 HiveServer2,我們只要實現 HiveServer2 定義的這套協議即可。透過相容 HiveServer2 協議,我們可以在不修改 Client 的情況下,將請求呼叫都轉發到 Flink SQL Gateway,並在 Flink 叢集執行。
上圖呈現的是 HiveServer2 和 HiveServer2 Endpoint 的對應關係。
HiveServer2 提供了直連 MetaStore 的能力,可以使用 Hive SQL,底層是批處理引擎,包括 MapReduce 或者 Spark 等。
HiveServer2 Endpoint 內建了 Hive Catalog,其實就是 Hive MetaStore。同時它也使用 Hive 語法,底層也是批處理引擎,即 Flink Batch 引擎。
講了這麼多關於 Hive 相容的內容,最後我們能達到什麼樣的效果呢?
上面的圖我們從上往下看。通常,使用者的 SQL 指令碼透過 Apache Zeppelin、Beeline 等客戶端提交作業,然後透過 Hive 的 JDBC 提交到 HiveServer2 中,再交由底下具體的引擎來執行。
基於上述介紹的 Flink 對相容 Hive 所做的工作,我們只需要將引擎層改成 Flink 將可以作業直接遷移到 Flink 上,從而達到了一個非常平滑且無縫遷移的過程。
三、流批一體引擎的收益
3.1 Hive SQL on Flink 構建流批一體引擎
基於 Hive SQL on Flink 構建了流批一體引擎,我們獲得了以下收益:
- 第一,統一流批引擎。降低維護成本,提升研發的效率。因為我們現在就一套引擎了,所以維護成本會非常低。
- 第二,流批一體數倉。我們透過流批一體引擎構建出了流批一體 SQL 層。藉此,我們可以把流批一體的儲存考慮進來,構建完整的流批一體數倉架構。
- 第三,Hive SQL 實時化。目前 Hive SQL 主要還是跑在批引擎上,每天做一次排程,產生結果。如果把 Hive SQL 遷移到 Flink 中,我們就可以很方便的將它實時化改造。只要把引擎模式設定成流模式,就可以將其實時化,數倉實時化改造的成本非常低。
- 第四,OLAP & 聯邦查詢。我們可以基於 Flink + Hive SQL 搭建 OLAP 系統。藉助 Flink 對各種資料來源的支援,以及對 Hive SQL 稍微進行擴充套件就可以實現聯邦查詢。
3.2 基於 Hive 語法進行聯邦查詢
聯邦查詢是指,查不同資料來源的資料,再寫到不同的資料儲存中。Hive 本身雖然透過 storage handler 提供了查詢不同資料來源的資料,比如 MySQL、Hbase 等,但相對來說還是比較複雜和不太完善。所以 Flink 就對 Hive 語法進行了擴充套件,使其它可以很方便的進行聯邦查詢。
首先我們看一下上圖中間這條非常典型的 Hive SQL,它將幾個表 join 一下,distribute by 再寫到下游。注意看一下紅色字,就是需要我們額外改造的內容,改造的成本非常低,只要在 Table 前面加上 Catalog 的那麼就能讀到不同 Catalog 的資料。比如說我們註冊一個 PG Catalog,直接把 PG Catalog 的名字加到這個表的前面,我們就能讀到 PG Catalog 的資料。
基於這樣一層改造和擴充套件,我們就能使用 Hive 語法查到不同資料來源的資料,再寫到不同的資料儲存。
四、Demo
在傳統的 Lambda 架構中,我們往往會有兩條不同的 pipeline:
- 實時的 pipeline,我們往往透過 Flink 將 Kafka 的資料進行打寬聚合寫入下游,並透過 Flink 寫入 HDFS 的最終表。
- 離線的 pipeline,我們則可以透過週期性地排程 Flink 作業將資料寫入到 HDFS 中。為了保持資料的正確性,在 Lambda 架構之中往往透過將批的結果回刷到 HDFS 中,保證資料的正確性。
當批作業回刷結束後,使用者可以透過應用層分析最終表的結果,進行實時大屏地展示,做相關的資料應用以及分析資料之中潛在的趨勢。
今天,我們則聚焦在資料回刷這一層,演示如何透過 Hive on Flink 構建流批一體引擎。
我們在 Kafka 中提前灌注了一些實時訂單表,在 HDFS 中灌注了之前已經有的一些歷史訂單表。
實時鏈路中,我們透過 Window 語義,按天級別將統計資訊直接灌入 HDFS 中,實時地獲取當前的銷售量。而離線鏈路中,我們則透過 agg 語法可以在第二天凌晨彙總當天的訂單資訊。透過資料回刷,我們就可以得到統一的每日銷售額統計。
下面用 Zeppelin 演示 Hive SQL on Flink 構建流批一體數倉的 Demo。
demo 演示:https://www.bilibili.com/video/BV1GM411N7bK/
五、未來展望
以下是我們未來的一些規劃:
在流批一體方面,雖然我們在這個版本已經做了極大的努力,但儲存層仍然是不統一。比如在流上我們依舊使用 Kafka 作為中間結果的存放,在批上我們更傾向於使用 HDFS,因此儲存層統一也是至關重要的。另外,Batch 的使用者現在更傾向使用 Hive SQL 寫作業,但我們更希望他們能將 Batch 作業全部遷移至 Flink Batch SQL 中來。所以,未來我們將不斷提升 Batch SQL 的功能性。
在 Hive 的整合方面,主要分為以下 3 點:
- 最佳化讀各種格式的檔案,包括對讀 Parquet 檔案的巢狀列 PushDown、FilterPushDown 的最佳化等,從而提升效能。
- 提升寫 Hive 端到端的生產可用性。比如,批模式下解決小檔案多的問題。
- 根據使用者的反饋不斷加強 Hive 的語法支援。
在 Flink SQL Gateway 方面,它依舊處於起步的狀態。我們將從以下三個方面來完善它:
- SQL Client 支援向 SQL Gateway 提交 SQL,保證功能完整性。
- 補全認證功能,保證 SQL Gateway 基本生產可用。
- 基於 SQL Gateway 對接更多生態工具,增強 SQL Gateway 的應用範圍。
更多內容
活動推薦
阿里雲基於 Apache Flink 構建的企業級產品-實時計算 Flink 版現開啟活動:
0 元試用 實時計算 Flink 版(5000CU*小時,3 個月內)
瞭解活動詳情:https://free.aliyun.com/?pipCode=sc