幸福裡基於 Flink & Paimon 的流式數倉實踐

發表於2023-09-20
摘要:本文整理自位元組跳動基礎架構工程師李國君,在 Streaming Lakehouse Meetup 的分享。幸福裡業務是一種典型的交易、事務型別的業務場景,這種業務場景在實時數倉建模中遇到了諸多挑戰。本次分享主要介紹幸福裡業務基於 Flink & Paimon 構建流式數倉的實踐經驗,從業務背景、流批一體數倉架構、實踐中遇到的問題和解決方案,藉助 Paimon 最終能拿到的收益,以及未來規劃方面進行介紹。

點選檢視原文影片 & 演講PPT

一、業務背景

幸福裡業務是位元組旗下關於房產的業務線,圍繞這個業務有很多針對 BP 支援的方向,其中最重要的方向之一就是工單系統。工單系統面向的使用者是幸福裡業務線一線的經紀人和門店經理等。如下圖所示,我們可以看下透過工單系統,資料是如何產生和流轉的。

1

首先由經紀人將已完成的代看任務提交工單,後續相應的門店經理會對該工單進行稽核,在這個過程中就產生了兩條資料,並將其更新到業務庫的 Binlog 資料,作為實時數倉的資料來源進行計算後生成資料包表或直接用於一些考核系統。其中資料包表用於展示評估一線經紀人的工作是否達標等;考核系統則用於門店經理為一線經紀人設定考核任務量的工作系統,透過任務量標準自動反饋獎勵等。因此在以上應用的實時數倉建模上,我們發現房產類業務有兩個典型的特點:

  • 準確性要求 100%,不能有資料丟失和重複的情況發生。
  • 需要全量計算,增量資料在 MQ 留存時間有限,需要拿到全量資料 View 進行計算。

實時數倉建模特點

2

在實際業務的實時數倉 Pipeline 中,進入實時數倉前有多個資料來源,每個資料來源的特點也都不同,所以實時增量部分會存在 MQ 中,全量資料則是存在 Hive 中。

3

上圖實時數倉中的每一層都是由一個 Flink Streaming SQL 串聯起來的,DW 層的主要功能是把多個資料來源進行 Join 打寬,透過計算出來的寬表實現直接輸出進 MQ 中。由於 MQ 的留存時間有限會形成一個小時級或天級的週期性任務,在一個週期結束後 MQ 中的資料最終會落到 Hive 裡。DWM 這一層主要的作用是聚合計算,聚合計算的結果也會直接輸出到 MQ 中。每一層的計算模式都和上一層相同,實時數倉的計算結果會透過 Service 層服務於線上的資料應用,比如上面提到的資料包表和考核系統。每層輸出的 Hive 離線資料可以用於 BP 同學做資料排查/驗證等離線查詢工作。

回顧實時數倉的兩個特點,一是準確性要求 100%,也就是說要求整個數倉的實時任務狀態運算元都要維護全量資料;二是需要全量計算,是指由於異構儲存,實時資料存在 MQ,歷史資料存在 Hive,那麼就使得每層消費的 MQ 都需要實時消費增量資料和 Hive 全量資料。從開發工程師的視角這套實時數倉模型存在如下痛點:

4

在開發過程中需要時刻關注業務邏輯之外的邏輯,比如在 SQL 中對資料的重複處理;在資料去重過程中,使用單一欄位處理不夠精準,需要引入 Nanotime 做非確定性計算來解決問題等。之所以存在以上問題,主要是因為在整個鏈路中,實時資料和離線資料是分開儲存的,這種儲存異構使得兩部分的資料天然很難對齊。

5

這裡的資料運維包含三個部分:資料排查、資料驗證和資料訂正。存在的問題是,在資料排查和資料驗證的過程中,如果發現某條鏈路上的某個 SQL 作業需要訂正。訂正完成的 SQL 的結果輸出到 MQ 中,需要再將 MQ 中的資料落盤到儲存中的操作會產生 T+1 的代價。另外在訂正過程中的中間結果回退會直接暴露給使用者。

第二個問題是如上圖紫色部分是一個簡化的鏈路,而在實際生產過程中的複雜度很高,體現在主鏈路上的是一些表和任務會被其他很多工或表依賴,使得訂正過程會影響到很多不可預知的表或任務。造成以上問題的原因,主要有兩點,一個是資料訂正產生結果回退暴露給使用者,另外則是血緣關係複雜且需要人為維護。

6

在當前的這條鏈路上,Flink 實時任務的狀態維護是非常大的,這就造成儲存和計算資源的消耗非常大,從這麼大的狀態中恢復作業的過程也會很慢。產生狀態大問題的兩大原因主要是去重運算元維護全量資料狀態和級聯 Join 狀態重複。

為什麼選擇 Paimon

基於以上存在的痛點,我們考慮希望透過 Flink 生態搭建 Steaming Lakehouse 的組合來解決原始鏈路上的問題,如上圖所示,原始鏈路存在的問題有:

  • 儲存異構,Base+Delta 資料難對齊;
  • 去重引入非確定性計算和大狀態;
  • 血緣關係複雜 & 資料訂正結果回退暴露給使用者。

對應解決原始鏈路的問題,我們選擇了 Paimon:

  • 流批一體的儲存可以以統一 Table 對外輸出,實時和離線資料可以儲存到一張 Paimon 表中,直接解決了對齊的問題;
  • 不需要去重,Changelog Producer 代替狀態運算元,同時支援在儲存上產生完整的 Log,並將其持久化代替原有鏈路上的狀態運算元;
  • 血緣管理 & 資料一致性管理,支援無感知資料訂正。

二、流式數倉實踐

7

首先介紹流式數倉實踐過程中的架構設計,如下圖所示:

  • 儲存層選用了 HDFS 或 S3 的物件儲存作為儲存底座,選用 Paimon 作為統一的 Table 抽象;
  • 計算層選用 Flink 同一的技術棧,統一了流批計算;
  • 資料管理層實現了 Table 的血緣管理和資料的血緣管理,基於這樣的血緣管理可以做到資料一致性,血緣管理可以用於資料溯源的需求,為資料質量提供保障。
  • 資料一致性管理,流批一體 ETL 資料管理。在多表一致性聯調的時候,可以自動對齊資料,不需要開發人員手動對齊。

如上圖可見上層透過 Gateway 或 Service 層對外提供服務,終端使用者透過 SQL Client 或是 Rest API 訪問整個系統。

8

上圖是流式數倉 Pipeline。資料來源和前面提到的一樣,離線資料存在 Hive 中,實時資料存在 MQ 中。不同的是在進入 Streaming Lakehouse 的時候,設定了一個 ODS 層,這層會透過 Flink Streaming SQL 把每一個資料來源沉澱到 Paimon Table 裡。第二層是 DWD 層,透過對多個資料來源進行 Join 打寬的操作,將輸出的結果沉澱到 Paimon Table 裡。再透過最後一層 APP 層做指標聚合以及透出的工作。

由於中間資料都沉澱在 Paimon Table 中,所以開發人員在做資料排查和驗證的時候可以直接操作。透過上圖實時數倉的 Pipeline 可以看到儲存上是流批一體的,在計算上也是用 Flink 的技術棧統一了流批計算,這樣可以減少開發和運維的成本。而且中間資料沉澱也是可直接查詢的,不需要在運維的時候做更多繁瑣的操作。

9

在完成上述 Streaming Lakehouse 實踐落地後總結了如下收益:

  • 簡化開發流程

流批一體儲存可以解決實時和離線儲存異構的問題;

減少業務入侵,移除去重運算元,解決非確定性計算。

  • 提升運維體驗

中間資料可查;資料可追溯;

血緣關係 & 多表一致性,增強了多表關聯除錯能力,並且可以做到資料訂正無感知。

  • 減少狀態量

Changelog 持久化,可以減少30%的狀態量。

在實踐過程中,除了獲得了不少收益,也同樣遇到了新的問題,主要包括兩個:

  • 資料新鮮度差:端到端的延遲變化為分鐘級,資料新鮮度降低;
  • 小檔案問題:一些小檔案可能會影響讀寫效能。

三、流式數倉的調優

端到端延遲調優

10

首先要分析下整個鏈路資料的可見性與什麼相關。如上圖所示,Source 在收到資料之後,會把這些 Records 源源不斷的發給 Bucket,然後 Bucket Writer 在收到資料後,先把這些資料快取到一個基於記憶體的 Buffer,存滿之後會觸發一個 Flash 將這個 Buffer 裡的資料全部都 Flash 到磁碟上。這個時候就生成了對外不可見的資料檔案,只有當上遊觸發了一個 Checkpoint 的時候,整個鏈路中 Commit 運算元生成一個 Snapshot 指向剛生成的資料檔案才能對外可見。

分析整個流程,可以得出兩個結論:

  • 資料可見性與 Checkpoint 繫結。更嚴格的說是一個週期的資料可見性與 Checkpoint 週期嚴格繫結。
  • Checkpoint 週期 = Checkpoint interval + Checkpoint latency。Checkpoint interval 是 Checkpoint 觸發的頻率;Checkpoint latency 是整個完成一個 Checkpoint 所需的耗時。

11

因此在我們在做端到端調優的時候,是否只需要針對 Checkpoint 週期做相關調整就可以呢?最簡單的是不是將 Checkpoint interval 進行調小操作呢?

在得出結論前我們先來看下寫入流程。在 Paimon Sink 運算元中,Bucket Writer 會源源不斷的把資料開放到磁碟的資料檔案裡,另外 Paimon Sink 還包含另外一個元件 Compact Manager。這個元件主要是針對磁碟上的資料檔案不斷的做 Compaction。如上圖右側展示,Compaction 在邏輯上是個 Bucket,在儲存上是一個目錄,目錄下會存放很多資料檔案,這些檔案是由 LSM 樹組織的,分為多個 Level。實際上 Compact Manager 在做 Compaction 的時候就是針對這些不同層的資料做的過程。

所以我們推斷,整個 Compaction 過程是一個 I/O 比較多的操作過程,假設一味的調小 Checkpoint Interval,會導致頻繁的 Checkpoint,比如原來 100 條資料本來是能分一個檔案裡的,但是現在 Checkpoint 頻率過高後,這 100 條資料可能會被分到多個檔案裡,那麼每個檔案裡面的資料都會很小。其次,小檔案過多,會讓 Compaction 的整體代價變得更高,也會影響寫入的效能。其實這就是一個追求資料新鮮度的過程,主要需要在資料的寫入效能和資料新鮮度上做權衡。在經過多方實踐驗證後,推薦將 Checkpoint Interval 設定為 1-2 分鐘為優。

Checkpoint Latency 最佳化可以分為幾個方向進行:

  • Log-Based 增量 Checkpoint

利用 Flink 高版本的一些特性,如 Log-based 增量 Checkpoint 的方式去最佳化上傳階段的耗時。

  • 減少狀態量

比如減少上傳輸資料量,那麼上傳耗時就會減少。

  • Checkpoint 持續上傳

持續上傳本地狀態檔案。

  • 搭建獨立 HDFS 叢集

減少遇到慢節點的機率。

12

經過以上四種方向的最佳化,我們在實踐中得到驗證的結果是可以將端到端的延遲做到分鐘級。

小檔案最佳化

13

位元組內部的實踐是基於 HDFS 為儲存底座的,我們將小檔案定義為明顯小於 HDFS 上一個 Block 大小的檔案。小檔案引出最直接的問題就是檔案數量太多導致需要更多的 Block,比如 Create Block,Delete Block等,直接的影響就是 I/O 操作頻繁,會導致 HDFS 上的 NamaNode 壓力過大對穩定性產生影響;另外,無論檔案本身有多大,它的 Block 的元資訊是固定的,而這些元資訊都是存在 NameNode 記憶體裡的,過多的 Block 元資訊會造成記憶體 OOM 問題;當資料太分散/檔案數量太多時,資料就有可能被分配到更多的 HDFS 的 DataNode 裡,就會造成 DataNode 的來回跳轉,增加頻繁的隨機讀寫,使效率和效能變低;並且分配的 DataNode 變多遇到慢節點的機率也會變大。

14

在小檔案相關的問題中,決定是否產生小檔案的時機和因素有以下幾點:

  • 檔案生成。資料檔案在磁碟上生成是有兩個觸發時機的,一個是 Checkpoint 的時候,它會強制把當前的 WriteBuffer 裡的資料刷到磁碟上;第二個是 WriteBuffer,當它滿了也會把記憶體裡面的資料刷到磁碟上。如果把 Checkpoint Interval 調的過小,或是把 WriteBuffer 容量設定的比較小,那麼資料就會更頻繁的被刷到磁碟上,而產生過量的小檔案。
  • 檔案劃分。透過設定一些 Partition key 或 Bucket key,就決定了資料的走向,它會落在哪些檔案裡。比如,生產中實際數量非常小,同時又設定了過多的 Bucket,那麼可以預見,一個 Bucket 可以分到的資料量一定會比較小。這個過程中也會遇到小檔案問題。另外,如果設定 Partition key 或 Bucket key 不合理,可能會產生一些檔案傾斜的情況,即熱 Key 問題。
  • 檔案清理。Paimon 具有檔案清理機制,在 Compaction 過程中會刪除一些無用的檔案。另外,資料由 Snapshot 管理,如果 Snapshot 過期,就會從磁碟上刪除對應的資料檔案。如果 Compaction 觸發條件和 Snapshot 過期條件沒有管理好,也會造成冗餘的檔案留在磁碟上。

基於以上的介紹,分享一下我們在實踐過程中積累的一些小檔案調優引數,見下表所示。

  • Checkpoint interval::推薦在 1-2 min 比較合適;
  • WriteBuffer 大小:推薦使用預設值,除非遇到相關問題需要調整;
  • 業務資料量:可以根據業務資料量調節 Bucket 數,調整依據為單個 Bucket 大小在 1G 左右比較合適;
  • Key 的設定:可以根據實際的業務 Key 特點設定合適的 Bucket-key、Partition,以防產生熱 Key 傾斜的問題;
  • Compaction 管理和 Snapshot 管理相關引數:推薦使用預設值,除非遇到相關問題需要調整。

15

經歷了整個架構改造之後,我們將原有實時數倉鏈路做了對比,如下圖可見,在很多指標上都獲得了一定的收益。

  • 端到端延遲:在原始實時數倉開啟 Mini-batch 的情況下,端到端延遲沒有明顯退化,可以支援 1-2 min 的近實時可見;
  • 資料排查時效性:可以從小時級提升到分鐘級;
  • 狀態量節省了約 30%;
  • 開發週期縮短約 50%。

16

四、未來規劃

17

當前主要規劃了以下四個方向:

  • 首先,秒級端到端延遲的嘗試。可能會分幾期來做,計劃引入 Embeded Log System 來解決這個問題。長期來看,會把資料可見性與 Checkpoint 解綁;
  • 其次,資料一致性管理。血緣關係管理和資料一致性管理這兩個方面,在實際資料運維中是很有價值的;
  • 第三,狀態複用。狀態複用主要是解決 Join 狀態複用的問題。另外,我們希望可以做到中間狀態可查;
  • 第四,監控運維。未來當規模上去,希望可以建立監控體系,並做到指標可觀測。

Q&A

Q:請問在資料來源異構的情況下,是否考慮過其他入湖的技術選型?為何最終選擇了 Paimon?

A:在最初技術選型的時候,主要考慮幾個點,一個是跟 Flink 生態的結合,一個是 Streaming Warehouse 這種模型,當時與這兩點結合最好的是 Paimon,另外在我們 Steaming upsert 的主流場景下情況更優。

另外,對於中間儲存層,是 Plugin 的模式,不是說一定要和 Paimon 做很深的繫結。

Q:請問在做資料回溯、快照和回滾的時候,有做過哪些考慮?能夠給一些可供參考的建議?

A:在這個方面我們主要是基於 Paimon 做了血緣管理的功能。血緣關係管理簡單來講分為兩個部分:第一部分是表的血緣關係管理;第二部分是資料的血緣關係管理。

表的血緣關係管理,比如在提交作業的時候,透過任務可以提取出它上下游表的資訊,然後插入到引入的 System Database 裡。資料血緣關係管理,可以根據 Checkpoint 去劃分資料版本,一個 Checkpoint 完成之後就意味著一個版本資料的產生。然後再把具體消費了哪個版本的資料,記錄到 System Database 裡。

基於這兩種血緣關係管理,既可以保持舊鏈路線上服務的狀態,也能保障新鏈路回溯資料或訂正資料成為可能。在生產環境中,由系統層面把表自動切換,就可以完成一次資料回溯。

Q:請問用流本身去處理資料,如果資料量過大,是否會造成獲取資料來源開口的環節擁堵,以至於資料進不來?

A:這是一個寫入效能最佳化的問題,在 Paimon 官網上有專門針對這塊的詳細指導,大家可以去了解下。

點選檢視原文影片 & 演講PPT


Flink Forward Asia 2023 正式啟動

點選檢視活動詳情


更多內容

image.png

活動推薦

阿里雲基於 Apache Flink 構建的企業級產品-實時計算 Flink 版現開啟活動:
首購99元包月試用,有機會贏取定製周邊禮品!
產品官網:https://www.aliyun.com/product/bigdata/sc

image.png

相關文章