摘要:本文整理自集度汽車資料部門實時方向負責人、 Apache Flink Contributor 周磊&集度汽車資料開發專家顧雲,在 FFA 2022 行業案例專場的分享。本篇內容主要分為四個部分:
1. 集度實時計算發展
2. FlinkSQL 實時入倉實踐
3. Flink 計算平臺建設
4. 未來規劃
2021 年 3 月集度汽車成立。2021 年 11 月 Flink on native k8s 開始搭建。2022 年 4 月,集度汽車第一個實時計算任務上線,是一個小程式埋點實時入倉的 Flink SQL 任務。2022 年 9 月,Flink 計算平臺一期正式上線。那麼我們為什麼選擇 Flink on native k8s 的 Application Mode 呢?從業務現狀和技術現狀來講,我們公司有一個專業的 k8s 運維團隊和 Flink 從 0-1 開始建設,沒有遷移的成本。從 k8s 本身來講,k8s 有彈性、故障遷移、資源隔離和易於管理運維等優點。選擇 Native 方式的原因是基於原生的 k8s,HA 不再依賴於外部元件 Zookeeper。選擇 Application Mode 的原因是任務級別、資源隔離性更好,不存在資源搶佔的情況。那麼選擇了 Flink on native k8s 我們需要解決兩個關鍵點。第一個是 Web UI 暴露方式,第二個是日誌暴露方式。第一個關鍵點 Web UI 的暴露方式有三種,分別是 NodePort、ClusterIP、LoadBalancer。
1. NodePort:暴露一個 Node 的隨機埠,提供給外部流量訪問 k8s 叢集資源。
優點:啟動快,同網路環境可以直接訪問。
缺點:網路隔離情況下本地無法訪問線上任務的 Web UI;Node 埠數有限制,不能無限擴充套件。
2. ClusterIP:暴露 Pod IP+Pod Port。
優點:啟動快,不額外暴露 Node 埠,更省資源。
缺點:僅在 k8s 叢集內部或同網路環境中可以訪問,網路隔離情況下本地無法訪問線上任務的 Web UI。
優點:配置簡單,透過 LB 直接訪問線上 Flink 任務的 Web UI。
缺點:任務啟動比較慢,因為需要準備相關的 LB 環境;資源消耗大,每個任務都會啟動一個 LB;外網訪問帶來安全問題。
當然一般的雲廠商可以支援不啟動外網 LB 透過 kubernetes.rest-service.annotations 進行配置。
結合以上三種方式的優缺點,以及我們公司線上線下網路隔離的實際情況,我們最終選擇 ClusterIP+Ingress 的方式來訪問 Flink 任務 Web UI。
下圖是 Ingress 的配置樣例。每一個 Flink 任務都配置一個對應的 Ingress 資源,使用者透過 host 配置域名進行訪問,解析到對應的 Ingress Controller,然後透過 Ingress 配置找到對應 Flink 任務的 rest service 的 8081 埠。這樣就實現了透過域名訪問線上任務的 Web UI。
第二個關鍵點日誌暴露方式有很多種,比如寫本地檔案、寫 Kafka 以及其他外部儲存等。
我們選擇的是寫本地日誌檔案,選擇這種方式的原因主要是為了與第三方元件解耦,更加的靈活可靠。但是透過日誌元件列印的日誌檔案是在 pod 內部,而 pod 外部無法訪問。如果需要在 pod 外部獲取,需要將其對映到 Node 的磁碟上。下圖是日誌對映的配置檔案樣例。pod 內部的日誌目錄為/opt/flink/log 將其對映到 Node 磁碟/data/logs/flinklog 下對應的 Flink 任務名的目錄。這樣就實現了在同一個目錄下,只存在該 Flink 任務的日誌檔案,更容易進行日誌管理。如圖是集度實時資料流架構,資料來源分為日誌類、DB 類、埋點類、資料類。其中日誌類主要包括 server 端日誌、IT 系統日誌、安全系統日誌、各元件審計日誌等。埋點類主要包括雲端埋點、APP 小程式、官網、車端埋點。DB 資料指的是後端服務的 binlog 資料。資料類主要包括整車 CAN 訊號資料、感測器資料等。這些資料都流經 Kafka,然後透過 Flink 進行計算後寫入下游元件。下游元件主要有 Kafka、HDFS、Hive、Doris,ES 等。接下來分享一下集度實時入倉的工作原理和架構。在這之前,首先帶大家瞭解一下哪些場景適合使用 Flink SQL 進行實時入倉。目前集度使用了 Flink SQL 實時入倉的場景主要有日誌類資料實時入倉、埋點類資料實時入倉,包括前端埋點和服務端埋點。這一型別的任務沒有太過複雜的計算邏輯和額外需要管理的狀態,需要快速迭代,比較適合透過 Flink SQL 進行實現。對於這類場景來講,經常會有新增埋點欄位的需求。使用 SQL 方式將完全規避掉修改程式碼、重新測試、重新打包的繁瑣操作,直接在使用者 Flink SQL 部分增加相應的欄位即可。實時入倉主要有三個模組,分別是使用者 Flink SQL、Flink SQL 解析引擎、Flink Table Format。使用者編寫的 Flink SQL 交給 Flink SQL 解析引擎,引擎解析使用者 SQL 轉換為一個 Flink 任務,然後提交到 k8s 叢集。資料的解析邏輯是根據 SQL 中配置的 Format Type,透過 SPI 機制載入對應的 Table Format 工廠類來進行解析的。後續會分別對 Flink SQL 解析引擎、Table Format、使用者 SQL 這三部分進行闡述。第一個是 SQL 解析引擎。主要功能有三個,分別是解析並切分使用者 SQL;將 SQL 轉換為任務提交至 k8s 執行;Hive Catalog 管理。就實時入倉場景來講,對於 Hive 表,我們希望其後設資料持久化,由 Hive Metastore 進行管理;而其他表後設資料則不希望持久化,僅在 Flink Session 中使用即可。第二個是 Table Format。在 Flink 1.10 版本及以前,使用 Table Factory 這個工廠類,目前在 1.15 已經是 Deprecated 狀態。1.11 版本以後推薦使用 Factory 這個工廠類,目前我們使用的 Flink 版本是 1.13。就以 1.13 為例,來描述一下 Factory 相關的類結構。Factory 工廠類存在於 flink-table-common 包下,是 Table Source、Sink、Format 的基類。對於 Table Format,我們主要關注五個介面,分別是 Factory,DecodingFormatFactory,EncodingFormatFactory,DeserializationFormatFactory 和 SerializationFormatFactory。如果我們需要對某類資料進行自定義解析,可以實現 DeserializationFormatFactory 遵從 Jave SPI 原則即可。第三個是埋點入倉的 Flink SQL 樣例。可以分為三個部分,Source、Sink 以及 Insert 操作。1. 第一部分是建立了一個 Hive 的 Sink 表,可以看到透過 Flink Hive 的 Catalog 進行管理,該 Hive 表是一個小時級分割槽表。分割槽 Commit 的策略是建立 Succes 檔案的同時 Commit 相應的 Hive 分割槽。2. 第二部分是 Kafka Source 表,資料解析邏輯,由 Format 的配置項進行配置,其中 Watermark 是透過資料中的 evernt time 進行指定。3. 第三部分是 Insert 語句,將 Kafka 埋點中對應的欄位值寫到對應的 Hive 表中,以這樣的方式實現了將資料以某種 Format 指定的邏輯進行解析,然後透過實時流的方式寫到 Hive 和其他儲存中。在今年 4 月份我們在提交了第一個 Flink on native k8s 任務後,後續各個業務方向都想複用 Flink 實時計算的能力。比如以下三個場景:第一個是基礎的實時資料傳輸場景,業務方希望將業務庫的資料便捷的分發到多種儲存引擎中應對不同的需求。第二個是資料分析和大屏的場景,分發使用者在 APP 上的各種埋點資料來供後續的計算。第三個是車端的監控和挖掘場景,接入車端的埋點資料和訊號資料後,構建計算和儲存鏈路。在初始的開發階段,我們面臨多個開發痛點,比如每個使用者都需要手工維護自己提交的 Flink 任務,包括資源版本、配置、歷史提交等等。舉一個任務升級場景的例子,我們需要手工進行資源更新、編譯打包、編輯提交命令。資源由於沒有統一儲存的地方很容易搞混,導致線上的版本不是最後升級的版本。從開發角度來看,每個開發同學都需要了解 Data Stream API 和任務中每個配置的具體意義。對於不熟悉 Flink 的人來說,上手成本比較高。從任務維護角度來看,Flink 任務提交後缺少統一的日誌與指標收集,開發人員只能在任務失敗退出後,才能收到報警資訊,且在失敗後想拉取日誌、定位問題,目前也沒有統一的日誌搜尋和下載的入口。從叢集維護角度來看,我們還碰到了由於使用者不瞭解某些 Flink 原理,導致叢集資源佔滿,使其他任務一直處於資源申請狀態。或是多個使用者更改同一個配置檔案後,提交的任務沒有按照預期執行等等。比如經典的資料入倉場景,由於其他的使用者更改了 checkpoint 的配置,導致資料一直落不了倉。基於以上的問題,我們在 5 月份正式立項,開始建設集度內部 Flink 計算平臺。目前集度的 Flink 計算平臺已經上線三大功能模組,分別是服務管理、運維管理、資源管理。1. 多版本的資源管理:使用者可以自由切換資源版本。
2. 作業生命週期管理:作業從建立到結束的所有狀態變化都由平臺來維護。
3. 作業可配置引數管理:官方引數和平臺特有的定製化引數。
4. Flink 引擎多版本管理:根據使用者的具體需求,提供多版本的選擇,目前預設版本為 Flink 1.13。
運維管理層面,提供了豐富的任務指標看板,並基於這些指標定製化監控報警的功能,解決了上述所說的 Flink 任務黑盒問題。同時,為了便於使用者追溯與定位問題,建設了任務提交批次的概念,收集任務分批次日誌。資源管理層面,會管理每個任務提交所需的 CPU 和 memory 資源,防止每個任務無上限的申請資源,並對叢集的資源進行監控。一旦有大規模資源 pending 的情況,快速介入運維解決。下圖展示了我們當前 Flink 計算平臺的整體架構,主要分成三個部分。第一部分是我們的平臺服務。目前我們的計算平臺分佈在 k8s 的服務叢集上,統一走公司的服務註冊,複用已有的能力,比如服務釋出,域名管理,監控報警等等。第二部分是我們所有 Flink 任務執行的 k8s 叢集。這個叢集目前由我們和運維團隊一起維護,裡面的 k8s 資源由 Flink 計算平臺維護,子網地址等其他外部雲服務資源由基礎運維團隊維護。第三部分是我們依賴的一些基礎元件。比如利用公司的持續整合 CICD 來構建 docker 映象;日誌採集工具用來收集每個 K8s Node 上的日誌;搜尋引擎 ES 用來搜尋近期的 Flink 日誌;HDFS 用來儲存歷史所有的 Flink 日誌。以一個 Flink Jar 包任務為例,來看一下整體 Flink 計算平臺的處理流程。首先是任務提交時選擇的資源版本,因為用的是 Flink on native k8s 資源統一打包成 docker 映象。我們提供了兩種打包方式,主動上傳和自動觸發。主動上傳是指,使用者在上傳完成後可以選擇自己上傳的版本,來生成對應版本的映象,我們的映象管理服務可以將任務資源生成的各版本映象,上傳到公司自建的 docker 倉庫中。自動觸發的話,我們會打通公司的 CICD 為每個 Flink Git 專案的變更提交產生一個新的映象。映象生成的時候會根據使用者的配置來載入對應的 Flink 引擎版本,以及會從 HDFS 上拉取對應的依賴資源 Jar 包。
在映象生成後的任務提交階段,我們會針對每個作業定製化日誌對映配置和環境變數,來打通後面的批次日誌採集流程。這些配置都會應用在每個任務的 k8s 資源上。任務提交後,我們會利用 k8s 的 watch and informer 機制監聽每個任務所有資源資訊的變化事件,以及獲取到最新的 Flink 任務資訊後,來推動每個任務的狀態流轉。在任務執行階段,我們提供了三個任務執行狀態檢視的方式。
1. 使用者可以透過域名訪問 Flink Web UI。其原理主要是透過建立的 Ingress 資源來二次反向代理到任務的 rest service。
2. 使用者可以透過 grafana 來檢視每個任務的視覺化指標,Prometheus 會收集每個任務的執行指標。
3. 使用者可以檢視當前執行的日誌和歷史批次日誌。歷史批次日誌是日誌對映到 K8s Node 後,透過 Flume 收集到 Kafka,統一格式解析後流入 ES 和 HDFS,由統一的搜尋介面供使用者使用。
而實時執行日誌是透過 k8s 的 log watch 方式來增量獲取實時執行日誌的。
下圖是我們 Flink 計算平臺的頁面展示,可以看到平臺上每個作業的後設資料資訊和當前作業的狀態資訊等等。目前平臺管理了 100+的實時任務,接入的業務方包括數倉團隊、實時資料開發團隊、車雲鏈路團隊。下面展示的是我們 Flink 計算平臺在任務提交後的任務狀態流轉圖。一共列舉了九個狀態,接下來分別來講一下每個狀態的意義。started 是指任務成功提交後的初始狀態。jm pod running 是指 jm pod 資源申請成功狀態。任務在 started 狀態下,如果申請到 jm 的 pod 資源,會在 pod 正常執行後流轉到該狀態。pod running 是指任務所有叢集資源都申請成功的狀態,任務在 jm pod running 狀態下,如果申請到所有 tm 的 pod 資源,會在 tm pod 正常執行後流轉到該狀態。running 是指 Flink 任務執行態,收到 Flink 任務 running 狀態資訊後流轉到該狀態。not running 是指 Flink 任務非執行狀態,比如 tm 或者 jm 重啟,收到 Flink 任務非 running 狀態的資訊後,流轉到該狀態。success 是指任務成功狀態。stopping 是指任務停止中間狀態。前置狀態可以是多個狀態,如果使用者執行了停止操作,任務將流轉到該中間狀態。stopped 是指停止狀態,任務在 stopping 狀態下,如果收到資源確認、刪除資訊以後會流轉到該狀態。Failed 是指任務失敗狀態,任務在多個狀態下都可以流轉到該狀態。在未來的一年中,我們將使用 Flink 更好地支撐公司的需求,會繼續在平臺建設的迭代和湖倉一體的建設進行探索。計算平臺是實時業務的技術底層,也是 Flink 面向使用者的唯一渠道,我們將從三個方向不斷增強功能,提升使用者體驗和效率。1. 投入更多精力在 Flink SQL 的平臺化上,進一步降低使用者使用門檻。比如 SQL 語法校驗、SQL 除錯、統一管理後設資料等等。2. 嘗試實現資源的動態擴縮容。實現平臺自動化調整 Flink 作業資源,解決某些場景下業務資料增長帶來的問題。3. 穩定性建設和效能建設。比如作業在流量高峰如何保持穩定的效能;生產上會持續產生檔案的情況下,作業輸出的檔案如何進行調優等。
在湖倉一體方面,很多業務本質上還處於起始發展階段,我們會從一個新的業務方向落地一個湖倉一體的解決方案,慢慢的去探索和最佳化。在計算側我們主要會放在統一的資料模型、統一的 UDF、CDC 資料入湖,在儲存側我們將會探索一個統一的儲存引擎。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2936852/,如需轉載,請註明出處,否則將追究法律責任。