Flink 在螞蟻實時特徵平臺的深度應用

發表於2024-02-22

摘要:本文整理自螞蟻集團高階技術專家趙亮星雲,在 Flink Forward Asia 2023 AI 特徵工程專場的分享。本篇內容主要分為以下四部分:

  1. 螞蟻特徵平臺
  2. 特徵實時計算
  3. 特徵 Serving
  4. 特徵模擬回溯

一、 螞蟻特徵平臺

圖片

是一個多計算模式融合的高效能 AI 資料處理框架,能夠滿足 AI 訓練和推理場景對特徵低延遲產出、高併發訪問以及在離線一致等方面的訴求。

螞蟻建設特徵平臺的核心目的,是讓演算法同學在資料供給側能夠自給自足,即 data-self-sufficient。具體是希望演算法同學透過平臺以低程式碼的方式進行特徵研發、測試、釋出、上線,整個流程不需要專門資料工程團隊支援對接。

特徵上線以後,背後對應的高效能實時特徵生產任務、高效能查詢服務以及特徵在 “離線” 和 ”線上” 兩個世界保持資料一致性等功能由特徵平臺自動提供,對使用者透明。

特徵平臺從 2017 年開始建設,基於風控領域的積累和資料經驗把風控的核心資料產品抽出來,組建為特徵平臺。這套特徵平臺較好地服務了螞蟻風控的業務。在 19 年到 20 年期間,平臺向全站演算法業務推廣的過程十分困難。核心原因是基於風控建設的特徵平臺包含非常多風控業務語義,它的計算正規化是面向風控場景特別定製的,包括計算 DAG、資料精度、運算元型別等都是針對風控領域最佳化設計的,所以向全站推廣的過程中顯得難以適配。因此從 20 年開始,螞蟻特徵平臺進行了徹底的重構。

截止目前,螞蟻特徵平臺已經服務了螞蟻包括搜推,微貸,國際風控,網商,財富保險,芝麻等主要業務方。特徵規模 10 萬+,線上 Serving 的 QPS 兩百萬,日常的計算 TPS 100 萬左右。

圖片

想一套特徵平臺滿足全站特徵業務訴求,平臺應該具備的核心能力有以下 4 方面:

  1. 快速實現任意計算正規化的能力:
    首要訴求是演算法同學面對異構場景、差異需求能夠快速以配置化方式將實時特徵上線。所以特徵平臺不能和某種固定計算正規化繫結,需要具備快速實現任意靈活計算正規化的能力。
  2. 特徵大規模模擬回溯的能力:
    模型訓練的第一個階段是樣本準備。如果演算法同學想訓練一個模型,選好了一批實時特徵,而這些實時特徵還沒上線,意味著它沒快照,構建不出來樣本。因此對於這批新定義且未上線的實時特徵,特徵平臺需要快速計算出它們在歷史時刻面對歷史查詢請求的“瞬時值”,即特徵平臺能夠針對歷史樣本對新增未上線特徵進行特徵補全。這就需要特徵平臺具備大規模特徵模擬回溯的能力,對平臺提出了流批一致性的能力要求。
  3. 實時特徵冷啟動的能力:
    試想某個模型裡用了很多實時特徵,這些實時特徵又是視窗特徵,如果等實時特徵上線、視窗累計完整後再提供 Serving 服務,模型迭代效率非常低。這就要求實時特徵一旦定義好,要快速補全特徵視窗值,進而讓特徵儘快開始提供線上 Serving 服務,這就需要特徵平臺具備實時資料冷啟動的能力。
  4. 高效能特徵 Serving 的能力:
    模型上線後,要提供一個高效能的模型推理服務,依賴的資料輸入必須是高效能的。因為在模型服務的過程中,效能瓶頸點一般在資料 IO 階段,為了讓模型服務更高效、更準確,必須要提供一套高效能、低延遲的特徵線上查詢服務。這就需要特徵平臺具備高效能特徵 Serving 的能力。

圖片

根據四個必須具備的核心能力提出螞蟻新一代的特徵平臺架構 UFE(universal-featureEngine-based-architecture),這個架構橫跨離線和線上兩個資料世界。離線部分是一套用於特徵大規模模擬回溯的系統。線上部分用儲存把 “寫” 和 “讀” 兩側分開:“寫” 是基於Flink打造的一套實時資料生產系統。這套實時生產系統跟大規模模擬系統合起來的叫做 Skyline。“讀” 是一套基於自研高效能 SQL 引擎實現的高效能特徵查詢服務。其主要目的是給模型推理服務提供高效的特徵批次查詢服務,即如何把一批特徵在儘量短的延遲內返回給模型服務。

Serving 服務下面有一套用於特徵質量監控的 feature insight 體系。它可以實時監控特徵的呼叫情況、耗時情況,也可以分析特徵的內容分佈。如果內容分佈產生了急劇的變化則會產生警告。

架構最下面是特徵統一後設資料服務,這份服務的存在其實是很有意義的。把 feature-devops 的操作,包括特徵研發、定義、釋出、驗證,推送上線等全部抽象為介面。“特徵平臺管理時” 是基於這套介面實現的,如果有外部的大業務方想基於特徵平臺的核心資料能力去構建自己的平臺產品,也可以對接這套介面。在螞蟻執行的特徵看似來源於不同的配置平臺,其實進到特徵平臺內部後設資料是統一的。後設資料統一有一個極大的好處是無論生產側還是消費側特徵平臺做的任何技術最佳化,對全域性都是統一生效的。在螞蟻內部這套特徵後設資料系統已經對接了非常多的平臺,而 “特徵平臺管理時”,就像一套精裝公寓,如果沒有特殊需求可以領包入住。如果資源特別充裕且個性化定製訴求非常多,那可以基於特徵平臺的資料技術自己蓋房子。

二、特徵實時計算

2.1 特徵實時計算的挑戰

圖片

特徵實時計算面臨的第一個挑戰是效能上的挑戰。在螞蟻,動輒就會遇到一個計算任務要面臨大幾十萬甚至上百萬的 TPS 的情況。如何讓這種超大規模的計算任務能夠有低延遲穩定的輸出?這是一個巨大的挑戰。

第二個挑戰是希望使用者在平臺上只定義資料訴求,而不需要關心資料的具體是怎麼實現的。但相同的資料訴求在不同的場景下其最優的實現路徑可能完全不同(因為不同場景的資源情況、資料精度、延遲時長、資料查詢效能等要求都不同)。如何用一套實時特徵生產系統滿足差異化場景下最優計算路徑的快速適配?這是另一個挑戰。

舉 2 個場景的區別來說明這個問題:

  • 風控場景
    風控場景下長視窗特徵佔比非常高。例如 “使用者 90 天內的實時交易次數”、“使用者 90 天內日平均轉賬次數” 等等。長視窗的特徵佔比大是因為風控領域長視窗資料更能綜合判定使用者的可信度,且風控業務經常用長視窗資料和近期資料做比較來判別行為突變。再者風控需要快攻快防,一旦發現風險要立即改變資料口徑且立即生效。基於這兩個特性,在風控不太適合把這類特徵資料在計算側直接算成最終結果來提供 Serving(雖然這樣的對 Serving 效能是最好的)。因為首先超長視窗的實時計算現在還沒有引擎能夠將 State 全部放到計算引擎內部,其次面對快攻快防需要靈活調整資料口徑的訴求,完全預計算好的 KV 結果無法做任何程度的資料複用,一旦計算口徑發生改變,之前所有計算好的資料全部都無效了。因此在風控場景比較適合基於明細或者中間狀態的 Serving,也就是說在計算側,把明細或小時賬、天賬算出來存到儲存裡面去,特徵 Serving 時臨時從儲存裡把這些賬拿出來做聚合。
  • 搜尋場景
    在搜尋場景短視窗實時特徵佔比非常大。因為一般認為使用者近期的行為表現更能體現接下來的消費意圖。但搜推場景對特徵查詢效能要求非常高。例如一次查詢 100 個特徵,平均 RT 要在 10 毫秒以內,且長尾毛刺不能高於 80 毫秒(P99.99 的 RT<80ms)。要達到這種訴求,需要儘量把結果在計算側直接算出來,然後把它以 KV 化結構存到儲存裡供 Serving 使用。兩種場景的比較意味著看似差不多的實時特徵訴求,其實在不一樣的場景下最優實現路徑是不一樣的。也就意味著沒有辦法用一種計算正規化和一種計算的部署模式去服務全部業務。因此對特徵平臺提出一個要求,即平臺能夠靈活將使用者的資料訴求以場景化最優路徑來實現。

2.2 特徵計算框架 skyline 架構

圖片

基於這樣的考慮,提出了 Skyline 計算架構。Skyline 透過後設資料服務接收來自各平臺產品的實時特徵的定義(定義過程是面向計算需求的 DAG)。這個 DAG 會傳到場景化定製的 adaptor 層,被例項化為具體應該在這個場景最最佳化的計算方式。例如同樣 “求七天內的復登入次數” 到底是應該直接算出 KV 化的結果,還是在計算側算一些賬存到儲存中在特徵查詢時候臨時聚合呢?這個問題在這一層會確定。之後例項化的計算 DAG 會被流批通用的計算最佳化模組進行 DAG 到 Task 的拆分,然後對這些 Task 會做一些邏輯最佳化(filter 上推、列裁剪等)和計算 DAG 歸一化,其結果可以被流場景跟批場景識別邏輯執行計劃。這個邏輯執行計劃在批場景和流場景會各自應用各自的獨立專項最佳化,進而上線部署。

圖片

這裡面有 3 個關鍵階段:計算推導、計算歸一化、計算部署。

首先場景定製的規則外掛會將計算描述 DAG 根據 AGG 運算元型別和時間視窗長度例項化成不同的計算 Task,例如小於 1 天的 sum 直接使用 hopWindow 實現,大於 1 天的 sum 使用 tumbleWindow 計算天賬(特徵 Serving 時候查詢多天的天賬去二次聚合)。

圖片

接下來 Skyline 對計算 Task 進行 filter 上推、列裁剪、歸一化(節點順序調整和連結壓縮)進而形成由核心“骨架節點”組成的邏輯執行計劃。最後是計算部署,如果該場景要求絕對的任務隔離、追求不同計算之間不會相互影響,則歸一化後的邏輯執行計劃會被轉化成 Flink SQL 任務直接執行。如果計算資源緊張、追求最大叢集資源利用率,則 Skyline 會在全域性計算後設資料中進行查詢匹配,判斷現在叢集裡面有沒有相同骨架結構的物理任務,如果有 Task 會被合併到已有物理任務,如果沒有則新建一個物理任務(此類物理任務是用 stream API 寫的,可不重啟直接動態載入計算策略)。

圖片

在 Flink 裡面最直接的最佳化是儘可能縮減 Flink 的 State 的大小,State 越小任務穩定性越好,從而能夠讓實時計算任務在超大流量規模下做到低延遲資料產出。螞蟻有非常多的 “同質滑窗特徵”:“滑窗特徵” 即從現在到 N 久前的某種行為的聚合值,“同質” 即資料計算邏輯都一樣,只是最後查詢的視窗長度不一樣。如果這種滑窗場景用 Flink 原生的 hopWindow 實現,計算資源一定會無限膨脹且結果資料刷存在 IO 爆炸風險。因此對 hopWindow 的 State 進行了 “滑窗轉固窗” 的重構,資料到來會根據 eventTime 把它放到 merge 到固窗的 pane 裡面(pane 的長度為滑窗 slide 長度),在視窗刷出時根據 pane 裡的資料做二次聚合輸出。這樣極大的縮減了滑窗計算任務的 State,且同質計算完全可以基於這同一份 State 進行。同時更改了原始滑窗資料刷出機制,前後 2 個滑窗如果被判定資料完全一致,則不會刷出後一個視窗資料(因為 Serving 的時候都是查最新視窗的資料,如果後面視窗資料無變化則沒有必要刷出)。

圖片

特徵冷啟動主要利用了 Flink 天然的流批一致特性。將實時特徵生產邏輯轉化為等價的 Flink 批 SQL,線上上的實時任務提交之前先將 Flink 批 SQL 任務提交執行進行歷史資料補齊。之後把流任務從零點開始重置,這樣的流批兩邊的資料就可以拼接上。

三、特徵 Serving

圖片

特徵 Serving 的作用是給線上模型推理提供特徵查詢服務。實際場景中上層業務對特徵查詢效能要求非常嚴苛:一次查詢請求包含上百個特徵(由於資料鏈路的複雜性這些特徵對應的資料可能分散在不同儲存中),平均 RT 要求小於 10ms,P99.99<100ms。做到高請求、高併發情況下的低 RT 低長尾毛刺是 UFE-serving 服務的核心意義所在。

圖片

UFE-serving 由三層構成:

  • 表述層
    最上層是特徵的表述層,現在主推的特徵表述是 SQL,即使用者透過寫 SQL 的方式來定義資料從儲存查詢出後臨時轉換和二次加工的過程。

用 SQL 有三個好處:

  1. SQL 作為通用資料描述 DSL 沒有學習成本。
  2. 資料 Serving 的描述用 SQL 定義,計算的描述也用 SQL 定義,意味著面對同一個實時特徵可以根據實際場景靈活的做計算和查詢的推導和拆分。
  3. 最佳化全域性生效:由於特徵都是用 SQL 描述的,對 SQL 引擎做的任意最佳化都會立刻應用到全域性的特徵執行過程中。
  • IO 最佳化層
    IO 最佳化層遮蔽了底層異構儲存,將儲存都抽象為檢視的概念(SQL 中涉及到的表是 UFE 的檢視),特徵 Serving 引擎在一次特徵批次查詢過程會進行跨 SQL 的 IO 提取、合併及併發最佳化。
  • IO 例項層
    最下面是 IO 例項層,用於對接任意儲存。新的儲存出現,只要基於 UFE 公佈的 connector 介面實現一個 connector 例項,就可以把其納入到 Serving 體系裡面來。

圖片

具體一次特徵批次查詢的 IO 最佳化過程如下。

首先對資料進行分層抽象,例如使用者定義如下特徵 SQL:
select sum(amount) as total amount_24H
from trade_table
where gmt_occur between now()-24H and now();

SQL 中的 trade_table 就是定義的檢視,一個儲存會產生不同的檢視,同一個檢視又會產生不同的特徵。ufeServing 引擎會對一次批次特徵查詢涉及到的全部特徵 SQL 構建全域性最優 IO 計劃。構建過程是遍歷全部 SQL 收集列、視窗及檢視資訊,對這些 IO 資訊執行 “IO 分類合併” 演算法。演算法思想很簡單,首先根據檢視儲存型別進行 IO 分類,對於同一類 IO 將同行不同列及同表不同行的資料合併到一次 IO,同時基於 SQL 收集到的有效列、視窗範圍等資訊縮減單次 IO 的 scan 範圍。總的來說,一方面減少單次 Serving 過程中查詢引擎與儲存的互動次數,一方面減少資料 scan 的範圍,不同儲存併發查詢後引擎會將結果拆分到不同特徵。

透過 IO 合併最佳化和特徵 Serving 引擎內建的熱點自動發現、併發精準超時控制等技術,在特徵查詢側的長尾毛刺率能控在四個九以上,而且平均 RT 是非常低的。

四、特徵模擬回溯

圖片

實時特徵的值隨著時間軸的推移一直在變化,線上如此、離線也如此,特徵模擬就是要根據歷史驅動表(歷史特徵查詢流量)和歷史訊息表(例如歷史交易事件)算出某個特徵在全部歷史時刻的瞬時值。這種 Time travel 計算在風控和消費信貸場景屬於核心的必備能力,因為這些場景進行策略調整或新模型的迭代時需要充分評估新特徵可能對線上交易造成的影響,因此他們需要模擬的樣本量很多都跨半年以上。

圖片

如果使用者自己在數倉裡面寫 SQL,如果資料量小的話可以算出來。但當驅動表擴張到百億級別的時候,沒有任何一種計算引擎的原生計算方式能夠在短時間內完成這種計算,因為這會涉及到大量的資料 shuffle 和資料 join,資料膨脹相當嚴重。

圖片

特徵模擬的核心挑戰:大資料量在 PIT 語義下計算的效能和穩定性。首先要讓這種計算能算得動,其次要有穩定的輸出。

圖片

這個流程圖講了特徵模擬的核心流程。首先根據驅動表、特徵邏輯、及事件表進行資料預裁剪(剔除事件表中不可能被用到的事件,因為沒有查詢流量查它)。資料裁剪後進行拆賬計算,將明細資料計算成小時賬、天賬,並且對明細加時間分割槽(主要用於後面的資料裁剪)。同時對驅動表按時間片拆分,接下來用驅動表再加上拆出來的賬做二次聚合加工,把最終特徵算出來。

圖片

二次聚合過程:首先算出驅動流量對於該特徵的視窗開始和結束時間。然後根據計算出的視窗資訊到將日賬、兩端的小時賬拼過來,最後會將小時賬兩端的明細拼進來(因為模擬計算的資料產出精度跟線上保持一致,也是毫秒級的)。這時候再拼明細,比使用者原生寫的 join 方式的效能高很多。因為明細在上面資料處理的過程中,其實已經攜帶了時間分割槽了。在具體找明細的過程中,特徵引擎會根據他所屬的小時分割槽天分割槽對資料進行大量的裁剪。經過拆賬最佳化和二次聚合,特徵平臺就能支援這樣的大規模 PIT 計算了。大概百億的資料量、90 天的視窗,特徵平臺能保證一個特徵在 24 小時之內產出。

Flink Forward Asia 2023

本屆 Flink Forward Asia 更多精彩內容,可微信掃描圖片二維碼觀看全部議題的影片回放及 FFA 2023 峰會資料!

圖片

更多內容

圖片

活動推薦

阿里雲基於 Apache Flink 構建的企業級產品-實時計算 Flink 版現開啟活動:
59 元試用 實時計算 Flink 版(3000CU*小時,3 個月內)
瞭解活動詳情:https://free.aliyun.com/?pipCode=sc

相關文章