螞蟻實時低代碼研發和流批一體的應用實踐

摘要: 本文整理自螞蟻實時數倉架構師馬年聖,在 Flink Forward Asia 2022 流批一體專場的分享。本篇內容主要分爲四個部分:

    1. 實時應用場景與研發體系

    2. 低代碼研發

    3. 流批一體

    4. 規劃展望

01 實時應用場景與研發體系

螞蟻實時的數據應用主要包括報表監控、實時標籤和實時特徵三部分。最底層的實時數據採集來源於線上日誌、實時消息和數據庫日誌三大塊,並由此構建了實時和離線的明細中間層,該中間層定義不同的主題域,如:流量、營銷、交易等。再往上構建應用層數據去支撐前臺業務的實時數據需求。

在這三個應用場景中,報表場景根據查詢特性的不同,實時數據會被存儲到 OLAP 引擎或 KV 庫,在應用層進行實時 / 離線數據的融合,來構建實時數據報表;而在實時標籤場景,將實時數據直寫到 Hbase/Lindorm 庫中,離線數據通過標籤平臺迴流至線上庫中;特徵場景和標籤場景鏈路類似,通過特徵視圖對流 / 批數據分別進行字段 Mapping。

以上的數據鏈路架構在研發、運維、消費的成本上均存在一定的問題,在開發階段,首先突出的是實時研發的效率問題,一個實時任務從需求對接到數據交付往往需要較長時間,如果涉及到離線回補邏輯,則還需開發離線兜底鏈路,並同步離線數據到線上庫中;在線上運維階段,雖然 Flink 一直在降低任務調優難度,但實時離線計算引擎的運維壓力是雙重的,往往需要互相翻譯口徑進行問題排查;在消費鏈路中,實時離線兩撥同學研發,往往報表會配置兩份,其工作量重複之餘,也會增加下游的數據使用成本。

最後再拋出一個實時中的老大難問題:長週期計算問題。支付寶大促活動頻繁,計算活動期間累計去重 UV 這類指標,研發運維成本一直較高,這也是我們嘗試在優化解決的問題。

螞蟻實時研發體系在去年完成了的升級,構建了基於實時元表爲載體的實時研發能力,從實時資產的定義、到實時代碼研發、到線上的實時質量監控,再到實時元數據消費,都是基於元表來完成的,在數據研發時可快速的引用公共的實時資產。對於此套能力體系,研發同學還是需要經歷相當多的研發過程,上圖標星的是我們希望能夠進行提效研發和縮短開發週期的環節,因此,我們推出了低代碼研發和流批一體能力。

02 低代碼研發

低代碼主要解決我們實時開發中的兩個大的命題:研發提效和降低實時研發門檻,對於這兩個問題面向的用戶羣體還不一樣。一類是資深的實時研發同學,他們比較瞭解實時研發中的各項細節,但是很多基礎性的代碼研發工作會極大影響他們的效率;另一類則是實時的入門級選手,他們對於實時研發的概念和使用方式都不太熟悉,可能是對照着 API 一步步試錯。

對於這兩個風格不一樣的人羣,他們本質的需求都是希望有個工具來解決他們的問題,由此我們構建了實時低代碼研發能力。本着產品易用、任務易維護、代碼正確的前提,我們通過配置化研發,將實時研發的範式抽象,並集成高階的實時解決方案,最後期望能夠強化任務自動化運維,讓用戶在低代碼中所配即所得,即配即上線。

我們優先從數據場景入手考慮低代碼研發工具所需具備的能力。彙總計算場景中,側重對統計週期和維度的各種組合,而指標計算大部分是累加型 (COUNT(1))、聚合型(SUM(xxx)) 和去重型(COUNT(DISTINCT xxx)),當然還需要具備簡單的邏輯過濾、維表關聯等基礎代碼操作。標籤場景中,側重對明細數據的處理和解析,需要能夠支持各種實時計算算子。特徵場景和指標計算場景很像,但是時間窗口多以滑窗爲主,計算近 x 分鐘 / 小時的窗口聚合數據,維度主要是 user 或 item 粒度(如計算商品、流量點位、店鋪等),特徵中計算算子較爲豐富,且一個需求中需提供多個滑窗、多種指標的特徵,需要能夠支持多窗口多算子的實時計算能力。

綜合以上三個場景,我們抽取三者共同的特點:算子支持、Flink 特性封裝、批量研發。

對於這麼多能力需求,我們採用維度建模的理論來進行構建,Flink 實時計算中三大 Connector(Source/Sink/Dim)和維度建模理論天然的契合,從明細事實表出發,進行一系列的數據操作,設定統計週期和維度,計算相應的實時指標。剩下就是對於低代碼能力細節的拆解,從用戶體驗、平臺能力和引擎優化三個角度進行構建。

整個平臺能力分爲用戶任務配置和代碼邏輯生成兩大塊。

在用戶操作界面,我們定義了關聯維表、數據膨脹、表級去重、表級過濾四大過程組件,並通過計算視圖這個能力兜底以上算子不能覆蓋的場景。同時定義統計週期和統計維度兩個結果組件,使用這兩個組件則默認是彙總指標計算,反之則是明細數據處理。對於這些組件中的信息,我們抽象了計算元素的概念,將重要的組件內容和來源表綁定,一些通用的計算範式和資產消費口徑,用戶可以直接選用其他用戶公共定義的邏輯,提高開發效率。

這樣通過添加組件,篩選維度和週期,對結果表中的字段定義其類型,並選擇具體的邏輯,調整維度分佈後,便完成了實時任務的配置。

任務配置完,平臺側從結果表反向推導,判斷任務配置的邏輯是否正確,這一步很像 Flink 執行計劃生成的邏輯,從後向前不斷循環校驗各算子的正確性,直至整個任務代碼生成,這便完成了代碼的編輯工作,用戶對物理任務進行執行計劃配置即可上線。

對於低代碼研發中引擎的優化,我以實時特徵舉例。首先我們來對比下指標場景和特徵場景的異同點,其最主要的差異在於窗口和算子的複雜度,同時特徵中多以用戶粒度也決定了下發數據相對較多,數據吞吐較高。

從以上這些現狀出發,我們對 Flink 的窗口計算做了一系列優化,首先從單滑窗升級到了多劃窗語義。根據下游使用橫表和豎表數據需求,將多滑窗中的窗口行轉列成多個指標,對數據進行拉橫,減少下游輸出的條數。

同時對觸發策略進行升級,可支持窗口觸發前後都能進行數據的更新,當然對於窗口觸發後主要用來進行數據置 0 的操作。對於定時更新的數據下發,考慮到下游的數據庫性能,對 Connector 加入了限流功能。還引入了對窗口狀態變更檢測能力,如果窗口內的數據沒有變更,也不需要進行下發更新。

對於多滑窗的狀態存儲優化,和 Flink 開源版本類似,加入了子窗的概念,一個數據保證其只劃分到最細粒度的窗口中,窗口計算時彙總各子窗中的數據即可完成數據聚合。

最後通過一個案例介紹實時低代碼研發的使用。

首先在來源表上定義計算元素,這些定義的邏輯可被過程和結果組件使用。配置面板中有三大塊:過程配置、結果組件和麪向結果表的字段定義,對於不同統計週期的相同計算邏輯,可使用批量複製,修改統計週期即可。

平臺還提供了統計週期和維度的組合拆分能力,用戶根據統計週期和維度的數據情況,選擇是合併一個任務還是拆分多個任務。

最後便是生成的代碼展示,這裏提到的是,平臺側會感知 UV 和 PV 的計算邏輯,並對 UV 類累計指標單獨拆成子任務計算,最後和 PV 類進行合併,用戶還能使用我們內置的累計去重計算方案。

03 流批一體

在構建流批能力之前,我們先 REVIEW 下當前實時數倉中的數據鏈路情況。Lambda 架構中,三個消費場景的實時離線數據融合方案還不統一,從數據側到應用側都有觸發流批數據融合的邏輯,但本質上還是流批模型字段對齊的語義表達,下游便可實現字段對齊邏輯。

其次在實時數倉中,大部分都是從 ODS/DWD 層直接計算累計結果,而離線數倉中,應用層數據大部分都是從輕度彙總層計算得到,在構建流批數據時需考慮這樣的差異,可能流和批表的對齊方式就是明細和彙總。

在頻繁的大促過程中,實時和離線任務存在着重複開發的問題。對於研發口徑一致性,實時離線報表指標對齊,都有着一定的挑戰。對此我們考慮多個方面,從字段對齊到引擎的生態,再到研發運維效率,並參考業界流批計算的案例,最終選用 Flink 引擎來構建流批一體的研發能力。

通過一套資產、一套引擎、一份代碼,完成流和批任務的研發,最終通過流批能力覆蓋實時離線重複開發和兜底的場景,提高研發運維效率。

螞蟻主流的實時研發引擎還是 Blink,對於通過 Flink 來構建流批研發能力,有很多的工作要做,我們規劃了五個大的時間節奏點

  1. 首先將開源 Flink 適配到螞蟻計算組件中,包括一些可插拔的組件,Connector 等,同時實時研發平臺還要對 Flink 新引擎進行兼容,並對標 Blink 之前的體驗進行能力的升級。

  2. 接着我們對 Hybrid Source 進行的 SQL 化定義,對 SQL 語法和 DDL 參數進行設計,同時引入了多源元表的能力,多源元表是在單源元表基礎之上,對字段進行映射。

  3. 第一版的多源元表只能進行簡單的字段映射,但發現往往流批 Source 表會出現字段不對齊、字段語義不一致、字段數量不相等的情況,這就引入了虛擬列和流批標識的能力,通過新增虛擬列,能夠將某一方沒有的字段補齊,並在代碼中通過流批標識顯式地對字段進行處理。

  4. 接下來對 Flink 批引擎進行了落地,和流引擎一樣先完成了生態和平臺的適配,接着便是對 Flink 批的運行參數,資源分配,併發推斷等能特性進行調試。

  5. 最後便是流批一體的能力的落地,在平臺側實現多源元表定義、代碼翻譯和任務運維,目前正應用在大促場景。

流引擎和批引擎在落地的過程中有很多相同的工作量,這裏主要介紹批計算引擎的架構。

首先是調度層,螞蟻 Flink 的調度使用了原生的 K8S 調度,我們還在嘗試集羣調度模式,在 K8S 之上直接獲取機器資源,減少任務發佈上線的時間,同時能保證任務的穩定性。

在引擎這一層,Flink 研發運維同學做了很多的工作,從上往下看,首先對齊 Blink SQL 完成計算函數的新增,並優化了部分執行計劃推斷的邏輯。如一個源抽取了 ab 字段,同樣的表抽取了 bc 字段,則會對 source 表進行合併讀取。

在批引擎執行優化層面,對批計算中的併發度、CPU 和內存進行配置,Connector 的併發度根據數據量進行推斷,而運行中搭配 AdaptiveBatchScheduler 進行動態調整。對於 CPU 和內存,則根據不同的算子類型進行設置。並對線上任務進行壓測,發現並優化 Flink 批在大數據量和計算壓力下的一些改進點,保證批任務的運行性能和穩定性。

Connector 層面則主要對齊 Blink 進行適配,考慮到批任務會在計算完成之後一次性同步會產生輸出洪峯,爲了保護線上庫,設置限流是相當必要的,引擎側在 Connector 插件中實現了限流的能力。

DataStream 引擎和算子主要使用開源能力。最後在可插拔組件中,我們主要對 Shuffle 組件、調度組件和後端狀態進行了適配優化。批任務默認使用基於 TaskManager 本地磁盤的 Shuffle 方式,這種方式對本地磁盤的要求比較高,在上下游交互的時候存在依賴關係,我們引入了開源的 flink remote shuffle 組件,獨立部分 Shuffle 組件,實現計存分離的架構。

在計算平臺層面,對批任務的預編譯、調試、提交、發佈、運行監控進行了支持,對於離線代碼中的時間變量、任務參數進行解析翻譯。其中最重要的是將 Flink 批計算類型加入到離線調度引擎中,依賴 Odps 等其它的任務產出的數據,在調度運行是生成任務實例,並查詢具體的運行日誌。

對於流批表對齊的問題,我們來看以上兩個 CASE。在流和批都是明細的情況下,流和批的字段含義不一致和不對齊是常見的,比如離線是否打標是 Y/N,實時打標 1/0。而對於流明細批匯總的場景,比如離線是算到用戶粒度的輕度彙總數據,對於 PV 這樣的字段,實時肯定沒有的。

對於以上這類問題,一個方案是某一方進行數據的改造,保證兩側的數據字段對齊,但是成本相當高。因此,我們設計了虛擬列字段,對於某一方不存在的情況下,使用虛擬列標識,同時對流表和批表進行參數定義,這樣就能在代碼中顯式的判斷和處理,以此來解決流批字段不對齊的問題,在這樣的能力支撐下,即使流和批表字段完全不一致的極端情況,也能進行特判和處理。

對齊來源表字段之後,我們來看下流批一體的整體方案。舉個栗子來簡述下具體的方案細節,有 stream_source 和 batch_source 兩個來源表,其中 c 和 d 字段是不對齊的,通過虛擬列進行補充,註冊成 mix_source 的多源元表,我們在正常開發流批任務的時候,根據流批標識進行邏輯判斷,同時也能通過代碼變量做流批的自定義邏輯。

平臺側會根據 mix_source 背後的單源元表進行物理代碼的翻譯,同時通過一個 View 的適配,將字段和虛擬列定義完成。批代碼我們支持靜態分區,也就是在 DDL 中定義分區,和動態分區,在代碼中顯示的指定時間變量,以此對離線分區進行裁剪。當然對於維表和結果表,當前只能支持單源或者字段完全一致的多源,這塊目前沒有特別強的訴求,需要將維表和結果表也要支持不同的字段定義。

對於長週期去重計算指標,如大屏場景對數據結果查詢性能有一定的要求,往往需要將數據計算到一個指標或者很小量級的數據,能夠快速的進行累加。

對於這類場景,在沒有應用 Hybrid Source 之前,我們通常的做法是藉助 Hbase 這樣的 KV 庫,存儲用戶的訪問狀態,數據過來是校驗用戶是否訪問過,最終算到天級的新增 UV 開窗累計即可。另一種方向則是直接在 Flink 中設置較大的狀態過期時間,相當於把外部存儲內置到引擎中,但此種方案需要考慮,如果在任務出現問題,狀態需要丟棄,或者中途修改邏輯的情況下,實時回刷成本很高。

對於以上兩個問題,我們設計通過 Hybrid Source 來支撐。Hybrid Source 也是使用多源元表,映射實時和離線字段,我們定義了 Hybird Source SQL 的 DDL 語義,0 和 1 標識批和流表,同時定義了 fieldMappings 字段來標識字段名稱不對齊的情況,定義 virtualFields 表達虛擬列,在 Connector 插件中根據這些定義和流批標識,對數據進行打標,實時任務即可完成 Hybrid Source 場景複雜 SQL 開發。右下角圖片是 Hybrid Source 任務發上線的啓動界面,對於批和流分別選擇啓動的時間。

讓我們看下這個流批一體的案例,需求是開發雙十一活動中的權益領取覈銷情況,我們通過 Mix 元表定義了實時和離線明細表,在代碼裏面顯式的處理了流和批不同的邏輯,實時側會對任務開始時間和延遲數據做處理,批則會限制調度日期的數據。

同時該任務開發了 Bitmap 的自定義函數,實時和離線共用一份 UDX 進行計算,最後分別對流和批元表進行參數配置,設置調度屬性後即可完成上線,上線後生成兩個任務,分別進行運維。

04 規劃展望

對於本次分享的低代碼和流批一體能力,後續會不斷的拓展使用場景,將實時數據應用到更多有價值的地方。同時在實時研發提效和降低門檻這件事情上,會繼續往前走,後續兩個功能穩定且用戶積累一定程度後,會嘗試將能力進行整合,在低代碼中實現一站式開發。最後則是看向業界都在探索的數據湖命題,希望能夠在幾個業務場景中將這套較大的解決方案落地。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/HbgePA7mDNFtNE9_p8FtlQ