Flink 1.11中對接Hive新特性及如何構建數倉體系

分享嘉賓:李銳 阿里巴巴 技術專家

編輯整理:馬小寶

出品平臺:DataFunTalk

導讀:Flink從1.9.0開始提供與Hive集成的功能,隨着幾個版本的迭代,在最新的Flink 1.11中,與Hive集成的功能進一步深化,並且開始嘗試將流計算場景與Hive進行整合。本文主要分享在Flink 1.11中對接Hive的新特性,以及如何利用Flink對Hive數倉進行實時化改造,從而實現批流一體的目標。主要內容包括:

  • Flink與Hive集成的背景介紹

  • Flink 1.11中的新特性

  • 打造Hive批流一體數倉

01

Flink與Hive集成的背景介紹

爲什麼要做Flink和Hive集成的功能呢?最早的初衷是我們希望挖掘Flink在批處理方面的能力。衆所周知,Flink在流計算方面已經是成功的引擎了,使用的用戶也非常多。在Flink的設計理念當中,批計算是流處理中的一個特例。也就意味着,如果Flink在流計算方面做好,其實它的架構也能很好的支持批計算的場景。在批計算的場景中,SQL是一個很重要的切入點。因爲做數據分析的同學,他們更習慣使用SQL進行開發,而不是去寫DataStream或者DataSet這樣的程序。

Hadoop生態圈的SQL引擎,Hive是一個事實上的標準。大部分的用戶環境中都會使用到了Hive的一些功能,來搭建數倉。一些比較新的SQL的引擎,例如Spark SQL、Impala,它們其實都提供了與Hive集成的能力。爲了方便的能夠對接上目前用戶已有的使用場景,所以我們認爲對Flink而言,對接Hive也是不可缺少的功能。

因此,我們在Flink 1.9當中,就開始提供了與Hive集成的功能。當然在1.9版本里面,這個功能是作爲試用版發佈的。到了Flink 1.10版本,與Hive集成的功能就達到了生產可用。同時在Flink 1.10發佈的時候,我們用10TB的TPC-DS測試集,對Flink和Hive on MapReduce進行了對比,對比結果如下:

藍色的方框表示Flink用的時間,桔紅色的方框表示Hive on MapReduce用的時間。最終的結果是Flink對於Hive on MapReduce大概提升了7倍左右的性能。所以驗證了Flink SQL可以很好的支持批計算的場景。

接下來介紹下Flink對接Hive的設計架構。對接Hive的時候需要幾個層面,分別是:

  • 能夠訪問Hive的元數據;

  • 讀寫Hive表數據;

  • Production Ready;

1. 訪問Hive元數據

使用過Hive的同學應該都知道,Hive的元數據是通過Hive Metastore來管理的。所以意味着Flink需要打通與Hive Metastore的通信。爲了更好的訪問Hive元數據,在Flink這邊是提出了一套全新設計的Catalog API。

這個全新的接口是一個通用化的設計。它並不只是爲了對接Hive元數據,理論上是它可以對接不同外部系統的元數據。

而且在一個Flink Session當中,是可以創建多個Catalog,每一個Catalog對應於一個外部系統。用戶可以在Flink Table API或者如果使用的是SQL Client的話,可以在Yaml文件裏指定定義哪些Catalog。然後在SQL Client創建TableEnvironment的時候,就會把這些Catalog加載起來。TableEnvironment通過CatalogManager來管理這些不同的Catalog的實例。這樣SQL Client在後續的提交SQL語句的過程中,就可以使用這些Catalog去訪問外部系統的元數據了。

上面這張圖裏列出了2個Catalog的實現。一個是GenericlnMemoryCatalog,把所有的元數據都保存在Flink Client端的內存裏。它的行爲是類似於Catalog接口出現之前Flink的行爲。也就是所有的元數據的生命週期跟SQL Client的Session週期是一樣的。當Session結束,在Session裏面創建的元數據也就自動的丟失了。

另一個是對接Hive着重介紹的HiveCatalog。HiveCatalog背後對接的是Hive Metastore的實例,要與Hive Metastore進行通信來做元數據的讀寫。爲了支持多個版本的Hive,不同版本的Hive Metastore的API可能存在不兼容。所以在HiveCatalog和Hive Metastore之間又加了一個HiveShim,通過HiveShim可以支持不同版本的Hive。

這裏的HiveCatalog一方面可以讓Flink去訪問Hive自身有的元數據,另一方面它也爲Flink提供了持久化元數據的能力。也就是HiveCatalog既可以用來存儲Hive的元數據,也可以存Flink使用的元數據。例如,在Flink中創建一張Kafka的表,那麼這張表也是可以存到HiveCatalog裏的。這樣也就是爲Flink提供了持久化元數據的能力。在沒有HiveCatalog之前,是沒有持久化能力的。

2. 讀寫Hive表數據

有了訪問Hive元數據的能力後,另一個重要的方面是讀寫Hive表數據。Hive的表是存在Hadoop的file system裏的,這個file system是一個HDFS,也可能是其他文件系統。只要是實現了Hadoop的file system接口的,理論上都可以存儲Hive的表。

在Flink當中:

  • 讀數據時實現了HiveTableSource

  • 寫數據時實現了HiveTableSink

而且設計的一個原則是:希望儘可能去複用Hive原有的Input/Output Format、SerDe等,來讀寫Hive的數據。這樣做的好處主要是2點,一個是複用可以減少開發的工作量。另一個是複用好處是儘可能與Hive保證寫入數據的兼容性。目標是Flink寫入的數據,Hive必須可以正常的讀取。反之,Hive寫入的數據,Flink也可以正常讀取。

3. Production Ready

在Flink 1.10中,對接Hive的功能已經實現了Production Ready。實現Production Ready主要是認爲在功能上已經完備了。具體實現的功能如下:

02

Flink 1.11中的新特性

下面將介紹下,在Flink 1.11版本中,對接Hive的一些新特性。

1. 簡化的依賴管理

首先做的是簡化使用Hive connector的依賴管理。Hive connector的一個痛點是需要添加若干個jar包的依賴,而且使用的Hive版本的不同,所需添加的jar包就不同。例如下圖:

第一張圖是使用的Hive 1.0.0版本需要添加的jar包。第二張圖是用Hive 2.2.0版本需要添加的jar包。可以看出,不管是從jar包的個數、版本等,不同Hive版本添加的jar包是不一樣的。所以如果不仔細去讀文檔的話,就很容易導致用戶添加的依賴錯誤。一旦添加錯誤,例如添加少了或者版本不對,那麼會報出來一些比較奇怪、難理解的錯誤。這也是用戶在使用Hive connector時暴露最多的問題之一。

所以我們希望能簡化依賴管理,給用戶提供更好的體驗。具體的做法是,在Flink 1.11版本中開始,會提供一些預先打好的Hive依賴包:

用戶可以根據自己的Hive版本,選擇對應的依賴包就可以了。

如果用戶使用的Hive並不是開源版本的Hive,用戶還是可以使用1.10那種方式,去自己添加單個jar包。

2. Hive Dialect 的增強

在Flink 1.10就引入了Hive Dialect,但是很少有人使用,因爲這個版本的Hive Dialect功能比較弱。僅僅的一個功能是:是否允許創建分區表的開關。就是如果設置了Hive Dialect,那就可以在Flink SQL中創建分區表。如果沒設置,則不允許創建。

另一個關鍵的是它不提供Hive語法的兼容。如果設置了Hive Dialect並可以創建分區表,但是創建分區表的DDL並不是Hive的語法。

在Flink 1.11中着重對Hive Dialect的功能進行了增強。增強的目標是:希望用戶在使用Flink SQL Client的時候,能夠獲得與使用Hive CLI或Beeline近似的使用體驗。就是在使用Flink SQL Client中,可以去寫一些Hive特定的一些語法。或者說用戶在遷移至Flink的時候,Hive的腳本可以完全不用修改。

爲了實現上述目標,在Flink 1.11中做了如下改進:

  • 給Dialect做了參數化,目前參數支持default和hive兩種值。default是Flink自身的Dialect,hive是Hive的Dialect。

  • SQL Client和API均可以使用。

  • 可以靈活的做動態切換,切換是語句級別的。例如Session創建後,第一個語句想用Flink的Dialect來寫,就設置成default。在執行了幾行語句後,想用Hive的Dialect來寫,就可以設置成hive。在切換時,就不需要重啓Session。

  • 兼容Hive常用DDL以及基礎的DML。

  • 提供與Hive CLI或Beeline近似的使用體驗。

3. 開啓Hive Dialect

上圖是在SQL Client中開啓Hive Dialect的方法。在SQL Client中可以設置初始的Dialect。可以在Yaml文件裏設置,也可以在SQL Client起來後,進行動態的切換。

還可以通過Flink Table API的方式開啓Hive Dialect:

可以看到通過TableEnvironment去獲取Config然後設置開啓。

4. Hive Dialect支持的語法

Hive Dialect的語法主要是在DDL方面進行了增強。因爲在1.10中通過Flink SQL寫DDL去操作Hive的元數據不是十分可用,所以要解決這個痛點,將主要精力集中在DDL方向了。

目前所支持的DDL如下:

5. 流式數據寫入Hive

在Flink 1.11中還做了流式數據場景,以及跟Hive相結合的功能,通過Flink與Hive 的結合,來幫助Hive數倉進行實時化的改造。

流式數據寫入Hive是藉助Streaming File Sink實現的,它是完全SQL化的,不需要用戶進行代碼開發。流式數據寫入Hive也支持分區和非分區表。Hive數倉一般都是離線數據,用戶對數據一致性要求比較高,所以支持Exactly-Once語義。流式數據寫Hive大概有5-10分鐘級別的延遲。如果希望延遲儘可能的低,那麼產生的一個結果就是會生成更多的小文件。小文件對HDFS來說是不友好的,小文件多了以後,會影響HDFS的性能。這種情況下可以做一些小文的合併操作。

流式數據寫入Hive需要有幾個配置的地方:

對於分區表來說,要設置Partition Commit Delay的參數。這個參數的意義就是控制每個分區包含多長時間的數據,例如可設置成天、小時等。

Partition Commit Trigger 表示Partition Commit什麼時候觸發,在1.11版本中支持Process-time 和 Partition-time觸發機制。

Partition Commit Policy表示用什麼方式提交分區。對於Hive來說,是需要將分區提交到metastore,這樣分區纔是可見的。metastore策略只支持Hive表。還有一個是success-file方式,success-file是告訴下游的作業分區的數據已經準備好了。用戶也可以自定義,自己去實現一個提交方式。另外Policy可以指定多個的,例如可以同時指定metastore和success-file。

下面看下流式數據寫入Hive的實現原理:

主要是兩個部分,一個是StreamingFileWriter,藉助它實現數據的寫入,它會區分Bucket,這裏的Buck類似Hive的分區概念,每個Subtask都會往不同的Bucket去寫數據。每個Subtask寫的Bucket同一個時間可能會維持3種文件,In-progress Files表示正在寫的文件,Pending Files表示文件已經寫完了但是還沒有提交,Finished Files表示文件已經寫完並且也已經提交了。

另一個是StreamingFileCommitter,在StreamingFileWriter後執行。它是用來提交分區的,所以對於非分區表就不需要它了。當StreamingFileWriter的一個分區數據準備好後,StreamingFileWriter會向StreamingFileCommitter發一個Commit Message,Commit Message告訴StreamingFileCommitter那些數據已經準備好了的。然後進行提交的觸發Commit Trigger,以及提交方式Commit Policy。

下面是一個具體的例子:

例子中創建了一個叫hive_table的分區表,它有兩個分區dt和hour。dt代表的是日期的字符串,hour代表小時的字符串。Commit trigger設置的是partition-time,Commit delay 設置的是1小時,Commit Policy設置的是metastore和success-file。

6. 流式消費Hive

在Flink 1.10中讀Hive數據的方式是批的方式去讀的,從1.11版本中,提供了流式的去讀Hive數據。

通過不斷的監控Hive數據表有沒有新數據,有的話就進行增量數據的消費。

如果要針對某一張Hive表開啓流式消費,可以在table property中開啓,或者也可以使用在1.11中新加的dynamic options功能,可以查詢的時候動態的指定Hive表是否需要打開流式讀取。

流式消費Hive支持分區表和非分區表。對於非分區表會監控表目錄下新文件添加,並增量讀取。對於分區表通過監控分區目錄和Metastore的方式確認是否有新分區添加,如果有新增分區,就會把新增分區數據讀取出來。這裏需要注意,讀新增分區數據是一次性的。也就是新增加分區後,會把這個分區數據一次性都讀出來,在這之後就不再監控這個分區的數據了。所以如果需要用Flink流式消費Hive的分區表,那應該保證分區在添加的時候它的數據是完整的。

流式消費Hive數據也需要額外的指定一些參數。首先要指定消費順序,因爲數據是增量讀取,所以需要指定要用什麼順序消費數據,目前支持兩種消費順序create-time和partition-time。

用戶還可以指定消費起點,類似於消費kafka指定offset這樣的功能,希望從哪個時間點的數據開始消費。Flink去消費數據的時候,就會檢查並只會讀取這個時間點之後的數據。

最後還可以指定監控的間隔。因爲目前監控新數據的添加都是要掃描文件系統的,可能你希望監控的不要太頻繁,太頻繁會給文件系統造成比較大的壓力。所以可以控制一個間隔。

最後看下流式消費的原理。先看流式消費非分區表:

圖中ContinuoousFileMonitoringFunction會不斷監控非分區表目錄下面的文件,會不斷的跟文件系統進行交互。一旦發現有新的文件添加了,就會對這些文件生成Splits,並將Splits傳到ContinuoousFileReaderOperator,FileReaderOperator拿到Splits後就會到文件系統中實際的消費這些數據,然後把讀出來的數據再傳往下游處理。

對於流式消費分區表和非分區表區別不是很大,其中HiveContinuousMonitoringFunction也會去不斷的掃描文件系統,但是它掃描的是新增分區的目錄。當它發現有新增的分區目錄後,會進一步到metstore中做覈查,查看是否這個分區已經提交到metstore中。如果已經提交,那就可以消費分區中的數據了。然後會把分區中的數據生成Splits傳給ContinuousFileReaderOperator,然後就可以對數據進行消費了。

7. 關聯Hive維表

關於Hive跟流式數據結合的另一個場景就是:關聯Hive維表。例如在消費流式數據時,與一張線下的Hive維表進行join。

關聯Hive維表採用了Flink的Temporal Table的語法,就是把Hive的維表作爲Temporal Table,然後與流式的表進行join。想了解更多關於Temporal Table的內容,可查看Flink的官網。

關聯Hive維表的實現是每個sub-task將Hive表緩存在內存中,是緩存整張的Hive表。如果Hive維表大小超過sub-task的可用內存,那麼作業會失敗。

Hive維表在關聯的時候,Hive維表可能會發生更新,所以會允許用戶設置hive表緩存的超時時間。超過這個時間後,sub-task會重新加載Hive維表。需要注意,這種場景不適用於Hive維表頻繁更新的情況,這樣會對HDFS文件系統造成很大的壓力。所以適用於Hive維表緩慢更新的情況。緩存超時時間一般設置的比較長,一般是小時級別的。

這張圖表示的是關聯Hive維表的原理。Streaming Data代表流式數據,LookupJoinRunner 表示Join算子,它會拿到流式數據的join key,並把join key傳給FileSystemLookupFunction。

FileSystemLookupFunction是一個Table function,它會去跟底層的文件系統交互並加載Hive表,然後在Hive表中查詢join key,判斷哪些行數據是可以join的。

下面是關聯Hive維表的例子:

這是Flink官網的一個例子,流式表是Orders,LatestTates是Hive的維表。

03

Hive批流一體數倉

經過上面的介紹可以看出,在Flink 1.11中,在Hive數倉和批流一體的功能是進行了着重的開發。因爲Flink是一個流處理的引擎,希望幫用戶更好的將批和流結合,讓Hive數倉實現實時化的改造,讓用戶更方便的挖掘數據的價值。

在Flink 1.11之前,Flink對接Hive會做些批處理的計算,並且只支持離線的場景。離線的場景一個問題是延遲比較大,批作業的調度一般都會通過一些調度的框架去調度。這樣其實延遲會有累加的作用。例如第一個job跑完,才能去跑第二個job...這樣依次執行。所以端對端的延遲就是所有job的疊加。

到了1.11之後,支持了Hive的流式處理的能力,就可以對Hive數倉進行一個實時化的改造。

例如Online的一些數據,用Flink做ETL,去實時的寫入Hive。當數據寫入Hive之後,可以進一步接一個新的Flink job,來做實時的查詢或者近似實時的查詢,可以很快的返回結果。同時,其他的Flink job還可以利用寫入Hive數倉的數據作爲維表,來跟其它線上的數據進行關聯整合,來得到分析的結果。

推薦閱讀:

hive join 數據傾斜 真實案例

Hive性能調優 | 數據傾斜

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