Apache Flink 在鬥魚的應用與實踐

ApacheFlink發表於2022-03-24

摘要:本文整理自鬥魚實時計算負責人夏暢在 Flink Forward Asia 2021 行業實踐專場的分享。本篇內容主要分為四個部分:

  1. 背景介紹
  2. 實時平臺建設
  3. 實時數倉探索
  4. 未來發展與展望

點選檢視直播回放 & 演講PDF

一、背景介紹

img

鬥魚成立於 2014 年,是一家致力於為所有人帶來歡樂的,彈幕式直播分享平臺。在鬥魚,實時計算髮展得並不算早。

2018 年前後,為了滿足一些近實時資料需求,如 5 分鐘、1 小時等場景,先後引入了 Spark streaming 和 Storm 技術。隨著業務的持續發展,實時指標的需求愈加多樣性,Spark streaming 和 Strom 也越加難以支援。

大概在 2019 年,鬥魚引入了 Flink 技術,起初以 Flink jar 的開發方式,來支援這類實時資料需求。但 Flink jar 的方式使用起來門檻和成本還是太高了。

在 19 年底 20 年初,設計開發落地了基於 K8s 的 Flink 實時計算平臺,同時支援以 SQL 和 JAR 兩種方式的作業開發,在內部這個平臺稱為 “玄武計算平臺”。

img

玄武計算平臺上線後,支撐了不少業務場景,如廣告、大屏,推薦、系統監控、風控,資料分析和實時標籤等。

img

截止到 2021 年 3 季度,鬥魚實時計算平臺的使用者數達到 100+,Vcore 達到 2000+,作業數達到 500+,日處理資料量超過千億條。

img

二、實時平臺建設

在建設玄武實時計算平臺之前,我們主要以 Flink jar 的方式開發,有以下幾個痛點:

  • 開發門檻高;
  • 部署成本高;
  • 沒有監控告警;
  • 沒有作業版本管理。

基於以上四點,我們設計開發了自己的實時計算平臺。

img

玄武實時計算平臺構建在 K8s 叢集之上,支援多個 Flink 版本,一站式實時資料開發平臺。架構上從上到下,可以分為四層:平臺層、服務層、排程層、以及 K8s 叢集層。

  • 平臺層:提供包括後設資料管理、作業管理、作業運維、案例示範、監控大盤、排程管理、告警管理等使用者互動功能。
  • 服務層:分為 Flink 作業服務和 Flink 閘道器服務,提供 SQL 校驗、SQL 除錯、作業執行、作業停止、日誌查詢等能力。
  • 排程層:藉助 K8s 的容器映象,實現 Flink 多個版本的共存。每個 Flink 版本都對應一個 K8s 的映象,從而實現作業版本的隨時切換。當然,為了實現一個 SQL 在多個 Flink 版本下通用,我們還做了一層 SQL 的對映,主要為了解決 Flink 版本間 connector 的配置差異。此外,我們還在排程層內提供了完整的作業狀態跟蹤機制。
  • K8s 叢集層:主要是提供基礎的執行環境。

img

上圖是實時計算平臺進行作業開發的例項圖。可以看到整個平臺提供如下能力:SQL 化作業開發、線上除錯、語法校驗、作業多版本、後設資料管理、配置脫敏、叢集管理、引數調優等。

搭建平臺的過程中,我們也遇到了不少的挑戰。

img

第一個挑戰是 Flink on K8s 叢集的部署資源問題。方案上,我們是使用 Standalone Kubernetes 部署,實際是在 K8s 的叢集中,建立了兩個例項組。一個例項組用來執行 JM 程式,另一個例項組用來執行 TM 程式。兩個例項組之間,通過設定 HA 的叢集 id 相同來實現繫結。

  • JM 例項組執行多個 pod 時,除其中一個作為 master 節點外,其他的 pod 都將以 StandBy 的身份執行;
  • TM 例項組執行多個 pod 時,每一個 pod 都將註冊到 JM 上,作為一個作業執行器存在。

為了使資源充分隔離,依託於 K8s 的能力,生產部署時,我們是一個作業建立一個 Flink 叢集。我們知道 K8s 建立一個 pod 時,需要指定 CPU 和記憶體的設定。而 Flink 叢集啟動的時候,需要在 Flink-conf 檔案指定 JM 和 TM 的資源配置。

在這個方案中,我們遇到的挑戰就是如何統一設定 K8s 例項資源與 Flink 叢集資源。

img

為了解決這個問題,我們改造了 Flink 映象啟動指令碼 entrypoint,在指令碼中增加了兩個操作:

  • 一個是拉取作業定義,以獲取作業的執行配置;
  • 第二個是替換 flink-conf 檔案 memory size 配置。

當然,在最新的 native kubenates 方案中,這個問題官方通過引數化配置解決了。

img

平臺遇到的第二個挑戰,就是如何去監控每個作業的執行狀態。方案上,我們將每個作業抽象成一條訊息,存放在基於 ZK 開發的訊息佇列中。並且在訊息佇列虛化了 5 個狀態,Accept、Running、Failed、Cancel 以及 Finish。

每個狀態都有一個獨立的執行緒池去監控消費。比如 Running 狀態,執行緒池從訊息佇列中獲取一條作業訊息,從中解析 Flink 叢集資訊,獲取 FlinkUI 域名,通過 K8s 的 Nginx Ingress,使用域名去訪問 Flink JM Pod,從而獲取執行作業的狀態。當獲取作業狀態還是 Running 時,將重入隊到隊尾,否則將移動到對應狀態佇列下。

img

實時計算平臺上線初期,我們又遇到了新的挑戰。在 Flink 的叢集中,如何讀取 Hive 表,以及如何使用 Hive-Udf 函式。

我們將一個 FlinkSQL 的提交拆分成三個部分:作業組裝、上下文初始化和 SQL 執行。

作業組裝,我們實現了 2 個方式:

  • 第一個是 SDK GET,通過 SDK 封裝的方法,請求平臺的服務層,去獲取作業定義;
  • 第二個是 FILE GET,直接讀取當前機器,指定路徑下的 SQL 檔案,生成作業定義。第二個方式主要是方便本地不依賴平臺服務,可快速除錯引擎。

上下文初始化部分,分為兩個過程:

  • 一個是調優引數的設定,類似常用 HiveSQL 的 Set 命令;
  • 另外一個就是 Catalog 初始化,而 Flink 叢集與 Hive 的整合,就是在整個環節實現的。

img

以 Hive 為例,在 Catalog 注入之前,平臺後設資料管理模組有一個 Catalog 初始化的過程,預先將 Catalog 的建立語句儲存起來。當一個 Flink 作業提交時,選擇需要注入的 Catalog。建立 Catalog,並註冊到 Flink 的上下文中,從而實現 Catalog 的元素注入。

img

隨著任務的增加,對於新手來說,在平臺上開發 Flink 作業,從 SQL 編寫到上線,往往需要改寫數十個版本。平臺缺少快速試錯的能力。所以我們設計開發了實時監控、實時除錯功能。

在架構方面,鬥魚引入了 Flink Gateway Server 對 Flink 叢集介面二次分裝。包含語法校驗、SQL 提交、SQL 狀態檢查、SQL 停止、SQL mock 等功能。將 Flink 叢集和閘道器服務的日誌統一收集。通過預啟動 Flink 叢集,縮短作業啟動時間,達到快速除錯的能力。

img

實時除錯主要分為四個步驟,即 SQL 解析、規則校驗、執行計劃,和物理執行。

SQL mock 就是改寫了原有的 SQL 解析過程。根據 SQL 解析後得到 Node 數,分析 SQL 的血緣關係,去判斷 Source 來源表和 Sink 目的表。動態的將 Source 表改寫為 dataGen 的資料來源,和 Sink 表改寫成 console 的資料來源。

img

動態修改 Source 和 Sink 表的配置,實現資料來源的 mock。這個帶來的好處是:線上開發 SQL 可直接用於除錯,不需要修改,並且也不用擔心會產生髒資料,可快速驗證 SQL 邏輯是否符合預期。

img

Flink 作業的監控告警,使用自定義 Metrics Reporter,將 metrics 指標上報到 Kafka 叢集,繼而使用 Flink 任務去消費 Kafka 裡的 metrics 資訊,完成如聚合、補充鏈路維度等操作,處理後的資料再推送到 Push Gateway,寫入 Prometheus 中。最後監控大盤基於 Grafana 繪製。

img

鬥魚的監控大盤分為資源監控,穩定性監控,Kafka 監控和 CPU 記憶體監控。

三、實時數倉探索

img

第一版實時數倉方案,借鑑離線數倉的分層與開發思路,以 Kafka 作為中間層的資料儲存。DB 和 LOG 資料分別經過 Canal 和打點服務寫入 Kafka,作為實時資料的 ODS 層。

  1. 消費 ODS 層,使用 Flink 做維度補充和清洗等操作後,寫回 Kafka,生成 DWD 層資料;
  2. 消費 DWD 層,以分鐘、小時的視窗,和指定維度產生聚合資料,寫回 Kafka,生成 DWS 層的資料;
  3. 最後消費 DWS 層的資料,寫入到 HBase、MySQL、ES、Redis、ClickHouse 等資料來源中,供資料服務使用。

img

隨著業務場景越來越多,這個方案顯現出了四個問題:

  • Kafka 資料保留時間有限;
  • 離線、實時資料儲存層不統一;
  • 中間層較難直接查詢分析;
  • 資料回溯場景不友好。

img

基於上訴問題,我們嘗試了第二套方案,使用 Iceberg 作為中間層儲存。利用前面提到的 Catalog 注入,我們注入了 Iceberg 的後設資料,將 DWD、DWS 層使用 Iceberg 來儲存。

這個方案解決了使用 Kafka 作為中間層的部分問題,但是又引入了新的問題。Flink 寫入 Iceberg 表時,資料的可見性依賴 Checkpoint 的 Commit 操作。因此 Iceberg 資料的延遲取決於 Checkpoint 的週期。而 Checkpoint 是阻塞式操作,往往不建議設定過於小。也就是說 Iceberg 作為中間層會比 Kafka 延遲高。對於時延要求高的場景就不太適合。

img

最終我們通過自定義後設資料服務,維護庫表的 Catalog 資訊,以及動態注入 Catalog 能力,實現雙方案並行。當然,我們也在繼續探索更加便捷的方案去開發實時數倉。

四、未來發展與展望

img

Flink 讓實時計算更加簡單,鬥魚在搭建實時計算平臺過程中也並非一帆風順。對於實時計算平臺未來的發展,我們有三個展望:

  • 第一個是 Flink 的動態擴縮容,實現平臺自動化,調整 Flink 作業資源,解決業務資料突增引起的問題;
  • 第二個是簡化實時數倉開發模型,降低實時數倉開發門檻,在企業內,將實時數倉真正大規模推廣使用;
  • 最後一個是完善實時資料質量監控體系,實現實時資料質量可驗證與可追溯。

點選檢視直播回放 & 演講PDF

更多 Flink 相關技術問題,可掃碼加入社群釘釘交流群
第一時間獲取最新技術文章和社群動態,請關注公眾號~

image.png

相關文章