螞蟻實時低代碼研發和流批一體的應用實踐
摘要: 本文整理自螞蟻實時數倉架構師馬年聖,在 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 來構建流批研發能力,有很多的工作要做,我們規劃了五個大的時間節奏點
-
首先將開源 Flink 適配到螞蟻計算組件中,包括一些可插拔的組件,Connector 等,同時實時研發平臺還要對 Flink 新引擎進行兼容,並對標 Blink 之前的體驗進行能力的升級。
-
接着我們對 Hybrid Source 進行的 SQL 化定義,對 SQL 語法和 DDL 參數進行設計,同時引入了多源元表的能力,多源元表是在單源元表基礎之上,對字段進行映射。
-
第一版的多源元表只能進行簡單的字段映射,但發現往往流批 Source 表會出現字段不對齊、字段語義不一致、字段數量不相等的情況,這就引入了虛擬列和流批標識的能力,通過新增虛擬列,能夠將某一方沒有的字段補齊,並在代碼中通過流批標識顯式地對字段進行處理。
-
接下來對 Flink 批引擎進行了落地,和流引擎一樣先完成了生態和平臺的適配,接着便是對 Flink 批的運行參數,資源分配,併發推斷等能特性進行調試。
-
最後便是流批一體的能力的落地,在平臺側實現多源元表定義、代碼翻譯和任務運維,目前正應用在大促場景。
流引擎和批引擎在落地的過程中有很多相同的工作量,這裏主要介紹批計算引擎的架構。
首先是調度層,螞蟻 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