網易遊戲實時 HTAP 計費風控平臺建設

PingCAP發表於2023-02-13

本文整理自網易互娛資深工程師, Flink Contributor, CDC Contributor 林佳,在 FFA 實時風控專場的分享。本篇內容主要分為五個部分:

  1. 實時風控業務會話
  2. 會話關聯的 Flink 實現
  3. HTAP 風控平臺建設
  4. 提升風控結果資料能效
  5. 發展歷程與展望未來

1.jpg

眾所周知,網易互娛的核心業務之一是線上互動娛樂應用服務,比如大家耳熟能詳的夢幻西遊、陰陽師等都是網易互娛的產品。不管是遊戲產品還是其他應用,都需要做出好的內容來吸引使用者進行應用內購買,進而產生盈利。

2.jpg

當使用者在商城裡點選商品進行購買的時候,會彈出支付介面,進行驗證、支付後,就可以收到道具了。這個過程對於使用者來說往往都是一些非常簡單的操作,但為了保證這個過程可以正確結算、發貨,整個支付流程其實跨越了很多服務提供商和終端,走了一條相當複雜的呼叫鏈路。這些不同的業務節點之間會產生很多相互的呼叫關係,進而產生一些異構的日誌、資料、記錄。

由於經過了網路,其中的資料可能會有一定時間水位線的不一致、延遲,甚至資料丟失的情況,且本身這些資料又很可能是異構的,就更增大了我們對這些資料進行分析和使用的難度。

如果我們需要用這些資料進行高時效性的故障排查或者風險控制,就勢必需要研製一套方案,來適配這樣技術需求。為了解決以上的問題,我們以 Flink 為計算引擎構建了一套實時風控平臺,併為他起名為 Luna,下面我將為大家進行詳細的介紹。

實時風控業務會話

3.png

常見的線上支付邏輯是,當使用者在應用上點選商城的道具進行應用內購買的時候,使用者的客戶端終端就會到計費系統進行下單,獲得本次下單的訂單資訊。

4.jpg

然後我們的客戶端會彈出支付介面,使用者進行渠道付款。

5.jpg

當支付完成後,我們會把渠道返回給客戶端的支付憑證回傳給計費系統,計費系統會去渠道驗證憑證是否有效。

6.jpg

如果是有效的,就會通知遊戲伺服器發貨,這個時候我們的客戶端才會收到道具。這就是從使用者點選到最終收到道具的整個流程。

7.jpg

從這個已經極度簡化了的支付模型可以看到,不同的公司、服務提供商、部門、服務系統會產生了一系列會話下的資料。如果我們能把這些資料收集起來,進行一定的處理後,還原當時使用者操作的現場。這將對運營運維人員在定位故障、排查故障,甚至整個業務環境的宏觀分析都有著非常重要的價值。

而分析的關鍵點是,我們如何還原這個行為的現場,我們把這個行為的現場叫風控業務會話,即由一次使用者行為所引發的,需要多個系統協作完成、同時觸發多個請求、產生跨越多個服務提供方呼叫的全過程。

這裡需要注意的是,業務會話跨越了多個相互獨立的請求鏈路,且沒有統一全域性的 trace-id 可以被提前置入所有的資料中。

8.jpg

由於我們的業務會話需要跨越多個請求鏈路,所以在資料關聯分析的時候就存在很多難題。比如

  • 多服務、多請求產生的異構結果難以直接關聯。
  • 呼叫順序複雜,存在併發、非同步的情況。
  • 時間跨度大、業務水位不同步。

以前在解決支付丟單、支付一次重複發貨等問題的時候,往往只能透過運營人員去處理,這就非常依賴於運維人員的經驗了。並且在這些大量的資料裡,會有非常多冗餘和無用欄位,還有可能會有一些非常複雜的巢狀關係。這些都有可能讓運維人員在判斷時產生錯判和誤判。此外,還會給運維人員帶來非常多的重複性工作,從而使得人力能效低下,把時間浪費在重複的事情上。

前文也提到了開源 Tracing 方案,往往需要依賴全域性的 trace-id。對於新的系統,我們可以提前設計 trace-id 打點。但是對於有歷史包袱的系統來說,他們往往不願意修改跟蹤來跟蹤打點,那麼這個時候傳統的方案就走不通了。

9.jpg

在這種情況下,如果我們要進行業務會話還原,就需要設計一套新的方案。這套方案我們希望可以具備以下功能:

  • 實時微觀業務會話檢索與查錯。
  • 實時宏觀業務環境統計與風控。
  • 業務會話級資料能效挖掘與提升。

10.jpg

從還原業務會話到使用資料做 HTAP 實時風控平臺的全過程,我們使用 Flink 消費原始資料,根據平臺上提前配置好的分析模板,實時還原出業務會話。然後把業務會話的結果儲存存起來,併為它打上我們提前設定好的一些結論模型,產生的風控結論。

對於儲存起來的這些微觀會話進一步被聚合,進而產生整個業務環境上的宏觀統計量,以支援我們在整個平臺上的風控分析需求。

會話關聯的 Flink 實現

Flink 是實時計算的實施標準,基於此我們毫無疑問地選擇了它。

11.jpg

那麼實時業務會話關聯在 Flink 系統上,我們希望可以做出怎樣的效果呢?

  • 第一,零侵入。即無需對現有業務進行改動,也無需有全域性的跟蹤 ID,就可以做到業務會話的還原。
  • 第二,跨資料來源。因為我們的業務往往需要跨越 n 種資料來源,所以我們希望這 n 種資料來源都可以被這個系統所支援,比如日誌、維表、事實表、REST 介面等。
  • 第三,實時。實時產生結果,無需等待 T+1。
  • 第四,低程式碼。我們希望基於分析需求,可以透過嚮導式的配置,來產生實時的分析模板,並對宏觀統計報表,可以配置式的進行多維度聚合。

12.jpg

上圖展示的是 JFlink-SDK,它是網易自研的一套流管理平臺以及它的開發手腳架 SDK。大家可以把它理解成是一套可以模組化配置式開發的流作業手腳架,實時關聯分析的引擎就是基於這套手腳架開發出來的。

13.jpg

回到在使用業務會話還原的問題上。來自各個資料來源的資料業務點,透過各種方式被同步收集到資料倉儲的儲存層中,我們有多種資料儲存收集這些資料。針對各種各樣的資料儲存,Flink 有非常豐富的 connect 可以進行消費。然後 JFlink-SDK 又對它進行了二次封裝,定義異構資料。使其在讀取到 Flink 的時候,可以被轉化成統一的檢視。

14.jpg

這些資料檢視是我們提前建設好的一些資料治理系統和平臺,資料治理系統會為 JFlink-SDK 提供資料讀取的規範。

15.jpg

當透過 SDK Source 讀取後,他們就會被統一轉化成業務檢視,這樣就非常方便我們後續對這些原始異構的資料進行關聯了。

16.jpg

它的資料結構是以基準和非基準共同構成的一種設計。在進行業務資料點關聯的時候,它的基本思想是基準+補充。所以我們在選擇業務時,會選擇最為核心的風控階段作為基準,也就意味著,基準是整個業務中最關鍵的步驟,可以用唯一的 ID 關聯起來。

對於透過業務 ID 關聯起來的基準,我們會形成一個類似圖的資料結構,這個東西我們稱之為基準簇,它由同一種資料來源的基準和補充所關聯得到的一個雪花狀資料結構。

17.jpg

基準是業務會話中最關鍵的步驟,它通常是公共攜帶的某種標誌步驟。比如以計費下單為場景,客戶端的下單,開啟支付介面、上傳憑證、支付完成是四個最為關鍵的步驟。他們都打上了執行這些步驟的訂單號,這四個步驟就可以作為整個業務規劃的核心步驟,也就是基準。因為資料是不按順序到達的,所以出現這是個步驟中的任意一個我們都可以開啟業務會話。

18.jpg

而下單記錄、商品詳情、渠道回撥記錄等等一些輔助性的資料,他們對問題定位起不了關鍵作用,而且它們可能沒有基準中訂單號的欄位,所以就沒有資格被選為基準。

但它們中也有一些欄位可以和基準中的欄位進行關聯。比如渠道回撥日誌,渠道商在一些輔助性的資料上打了 trans_id 欄位。它雖然沒有 order_id,但它可以透過 trans_id 與基準中的 trans_id 建立一一對映的關係,也就是我們可以透過 trans_id 關聯起這份資料與基準簇的關係。

所以透過基準+補充,我們就可以解決目前線上系統,無法為所有資料打上統一 ID 埋點的痛點。

19.jpg

在 Stream API 中基準關聯的實現,我們使用的是 Session Window。它是 Flink 提供給我們的標準時間視窗之一,可以在有資料流入的時候進行視窗時間超時的重置。除此之外,如果整條流的業務水位線,越過了整個超時時間的邊界,它就會觸發視窗計算。這種結果就非常適合由使用者觸發的會話視窗,也適合我們基準資料構造的邏輯。

但使用者引起的這種行為,往往時間是不固定的,所以帶有屬性的會話視窗就非常適配這種特性。比如風控業務會話的還原,和瀏覽商品到最終下單支付的整個支付應用軌跡的追蹤,都非常適合用這種模式來進行視窗計算。

這裡的 Flink Session Window 其實就是前文提到的構造完畢的基準簇,它包含了所有被關聯進來的原始資料,以及按照一定規則處理好的二級欄位。至於它怎麼在關聯的時候進行欄位抽取呢,後續再來討論這個規則,此處就先認為,在視窗完成的時候就把簇計算出來了,並完成了所需欄位計算和抽取。

20.jpg

一般使用者的支付意願視窗往往在 10~20 分鐘,如果我們直接使用 Event Time Session Window 來進行計算,就會發現如果使用者很快完成了下單,但系統仍然需要等待 10~20 分鐘,才能使會話視窗進行計算,這就大大降低了資料的時效性。

對此 Flink 也為我們提供了一口入口,我們可以自定義視窗的 Trigger 來設定視窗觸發的時機和業務會話提前結束的判定。

舉個例子,一些資料量極少的場景,它的水位線可能一直沒有向前推動,這種情況我們就可以加上 Process Timeout 和 FIRE & UPDATE 語義。這就可以讓業務會話在水位線沒有推進的情況下,先進行計算,往後傳送。然後在下游進行保證,即當上遊重複 fire 的時候,可以進行 update 的語義。

再舉個例子,我們可以在風控的分析模板中配置一下。當業務會話滿足某些條件的時候,就不用再等待超時了。比如當所有的節點都被關聯上時,如果繼續等待也不會等到任何節點,這個時候就無需等待超時時間,可以立即 fire 出結果。

21.jpg

當業務會話存在一些特殊且極端的情況,比如客戶端支付到一半崩潰了,等了非常久才起來,這個時候很可能就會被拆分為兩個業務會話,因為前一個業務會話已經超時了。這種時候我們會選擇把兩個被分裂的會話 fire 出來,然後由運維人員進行合併或者保持原樣。

22.jpg

接下來我們來討論一下,對於補充的資料我們又是如何構造的。基準資料擁有公共 ID,所以它們可以被 Key By 到資料視窗裡進行計算。但是補充資料點往往是各自用各自不同的 ID 進行關聯,所以這個時候我們就可以類比資料庫裡的多表 join 了。不同的補充資料就類似於一張不同的表,透過不同的欄位與基準資料簇進行 join 操作。

23.jpg

這就是我們遇到的挑戰,它不僅關聯欄位不同,水位線的推進速度也很可能不一樣,這都是無法把它們兩者放到同時間視窗中計算的關鍵因素。

那麼如何去解決這個問題呢?如何基於擴充套件的基準先進知識,關聯回沒有公共 ID 的補充資料呢?這正是整個解決沒有公共 trans_id 還能形成會話的關鍵所在。

24.jpg

類比 join 操作,Flink 已經為我們提供了非常好用的運算元,叫做 Interval Join。即兩種輸入資料分別取自己的特定欄位作為 key,然後透過這個 key 把他們分到同一分組上,進行時間區間內的 join。

Flink Event Time Interval Join 是把當前流和對手輸入流裡,指定上下邊界的區間內資料進行 join,這種特性就非常適用於我們這種場景,因為當我們從基準資料簇中取一個欄位,和從非基準的補充中取一個欄位,如果它們等值,那就意味著它們屬於同業務會話,它們應該進行關聯。

這個時候就可以用 Interval Join 運算元進行關聯,而且 Interval Join 不會開啟時間視窗,因為每條流的 GC Watermark 是根據對手流加上我們提前配置的邊界時間區間來進行的,這種結構就非常適合兩種資料流時間水位線推動不一致的情況。

25.jpg

但是還有另外一種情況,就是當某一條資料來源有延遲的情況下,這筆資料會被丟失,這是 Flink 1.16 正式版之前的情況。在 Flink 1.17 版本中,社群的小夥伴已經把這個程式碼合併進去了,後續很期待在新版本中使用這個功能。

26.jpg

當資料延遲進行補回的時候,我們的處理方式是,把延遲資料和當時關聯的上下文,放到訊息佇列裡,透過流重新消費出來,並根據當時關聯的上下文,重新從資料儲存裡把寫進去的會話查回來,然後用同樣的邏輯重新把這筆資料補回更新,寫回資料庫。

這樣整個過程中無論是實時關聯,還是延遲資料的補回,用的邏輯都是完全一樣的,保證了我們處理邏輯的簡潔和一致性。

27.jpg

最終我們用 Flink 實時關聯出來的業務會話會被儲存起來以供檢索,並透過 Luna 平臺以行為樹的形式進行展示。

HTAP 風控平臺建設

當我們完成了演算法可行性測試,並使用 Flink 實現了技術原型後。接下來就是如何把這一整套框架平臺化,使其成為便捷、準確、豐富的風控平臺。

28.jpg

風控平臺需要做到以下這些功能。

支援微觀排障,可以具體查詢某一筆訂單、業務會話當時的業務場景,把它還原出來;支援從宏觀上統計整個環境的各種資料量。且配置和查詢都需要是自助、嚮導式的。

29.jpg

基於以上的考慮,我們設計了 HTAP 實時風控平臺 Luna。基於這個平臺,使用者就可以自己從各種異構資料來源中選擇,配置業務行為樹和分析模板。然後平臺會根據配置好的模板,起 Flink 流算出業務會話的結果,形成會話結果存到儲存層。且支援使用者從平臺上進行條件檢索,進行多維度的聚合。

30.jpg

分析模板的配置我們是做了自動更新,也就是所有平臺上的更新都無需人工運維。

從上圖中可以看到,核心元件是計算層的 Flink,加上儲存層的 TiDB,加上我們自己基於 JavaScript 的平臺服務系統。目前可以達到微觀查詢是毫秒級,多維度的風控聚合結果在年級別都可以做到秒級查詢。

31.jpg

我們的平臺支援,使用者從不同的資料來源中選出,需要參與這一次關聯分析的資料和關注抽取的欄位進行配置。配置好後,Flink 會根據這些配置,自動生成出 Flink 的 Source 和 Sink。

32.jpg

然後進行行為樹的定義。定義整個業務行為會發生的動作,本質就是用人力運維排障方法論進行沉澱和泛化,將配置的形式固化下來。之後這些配置模板就會用於生成 Flink 流的 UDF 配置,並被實時同步到執行中的 Flink 流中。

33.jpg

除此之外,配置介面還提供了預覽功能,即可以一邊配置一邊預覽整個行為樹。

34.jpg

風控場景上的分析模板修改後,如果不涉及資料來源的增減,我們的流可以透過 broadcast stream 的特性進行自動同步和變更。

35.jpg

從架構圖中可以看出,我們選擇了 TiDB 作為關聯結果的儲存層。那麼我們是如何考慮的呢?

  • 資料結果需要靈活可擴充,且適配索引。這樣使用者就能快速的自由配置抽取欄位。
  • 頻繁的更新操作。因為我們的計算邏輯決定了我們會構造基準資料,再構造補充資料,以一種非同步的形式寫到資料庫,所以需要頻繁更新。
  • 完備的聚合函式。因為宏觀統計需要做各種各樣的聚合,以滿足我們資料分析統計的需求。
  • 滿足業務需求的寫入/讀取速度。

這樣就可以使用列轉行的結構,儲存到我們的關聯式資料庫裡了。

36.jpg

列轉行是把會頻繁發生增減欄位的 DDL 轉化為 DML,就可以支援我們靈活的資料結構。

37.jpg

每個欄位都需要索引這樣的特性,這在資料量持續增大的表上,就有著非常優秀的特性。

38.jpg

在這樣一種儲存結構上,我們的微觀業務會話查詢就可以做到毫秒級,靈活結合多種條件進行檢索,以幫助運維人員快速檢視線上風險和可能發生的故障原因。

39.jpg

當我們點選檢視任何具體的業務會話時,公共平臺就會展示出當前這個業務會話的業務行為樹,並抽取出有助於排障的一些關鍵欄位和二級指標,極大方便了我們的運維人員排查具體問題的場景。對於常見的問題,我們甚至還會用結論模型直接給出風控結論,讓我們的運維人員進去就能馬上看出問題所在。

40.jpg

對於宏觀統計,大家肯定也想到可以使用 SQL 作用在上面來進行統計了,畢竟我們把資料存在了關係型資料庫 TiDB 裡,但這裡還存在著一些坑點。

41.jpg

當我們的資料量超過 10 億的時候,我們的資料聚合時間會出現一些變化。比如當粒度是一小時,聚合時間是一天的時候,我們數秒可以完成。但當我們把時間拉到 60 天,幾乎就出不來了。

在檢視資料儲存層的時候會發現,TiKV 已經 IO 滿了,而且 CPU 飆升,因為我們做的資料量實在是太大了。

42.jpg

透過分析整個執行計劃可以看到,TiKV 使用常規的模式進行 SQL 把所有資料撈到 TiDB 層進行聚合計算。這樣做獲取的資料函式會非常多,隨著我們時間區間的增大會越來越緩慢,這樣我們肯定是不能接受的。

43.jpg

那麼我們來回看一下風控的 AP 需求,我們需要讀取大量實時的關聯的資料點;支援有複雜的聚合函式,且我們的查詢不應該影響到 Flink 流進行 TP 寫入。

這個時候就會想到,TiDB 有一個叫 TiFlash 的元件,它可以完成 TiDB 的 HTAP 特性。也就是 AP 和 TP 同樣用 SQL 來完成,且它是物理隔離的,這就非常的適用於這樣的場景。

44.jpg

TiFlash 偽裝成一個 Raft Learner TiKV 節點,加入 Raft Group,參與資料實時、事務性同步。這樣就可以做到 AP 和 TP 的物理隔離,並且它還支援事物,這樣就可以在執行 SQL 的時候無感進行 HTAP 了。

45.jpg

在進行這樣的最佳化後我們可以看到,當我們的查詢包含多層 join,甚至有分位數計算的時候,90 天聚合時間,粒度查詢可以在十秒內返回和完成,這可以說是一次質的飛躍。

46.jpg

最後,我們把宏觀統計提供給使用者。在 TiFlash 的助力下,我們的平臺可以做到秒級的 AP 多維度聚合查詢。這種聚合查詢出來的結果可以讓我們的資料分析人員,從更高層次對整個業務環境的風險進行識別。

提升風控結果資料能效

當我們可以實時產生業務會話的結果,並在平臺上展示的時候,接下來我們將透過以下幾點提高資料效能。

  • 風控結論生成:節約重複人力成本
  • 標籤和統計:將詳情資料歸類統計為宏觀資料
  • 資料打寬:增加分析維度
  • 視覺化展示:挖掘資料規律

47.jpg

那麼我們為什麼把資料儲存在 TiDB 這樣的一種關係型資料庫裡呢?

因為 TiDB 作為一個分散式資料庫,被我們廣泛儲存各項業務的事實和維度資料了。如果我們把風控資料簇也放在這裡面,透過簡單的專業操作我們就可以完成資料的拓寬,豐富我們的資料包表。

48.jpg

不僅是產生離線報表的時候可以這麼方便的轉,我們在實時計算的時候,也進行了 Async Join,透過 Async Join 轉 UDF 進行實時資料打寬,同時我們支援多種儲存介質。

49.jpg

對於這種 Async Join,我們利用了 Flink 的 Async IO 的特性,並在 join 的時候進行了一些最佳化。比如進行批的 join,不同時間水位線的快取 join 以及 timeup 資料的側輸出等等,這些都為資料的準確性提供了保障。

50.jpg

透過資料打寬後,我們的風控統計分析維度就可以更上一層樓了。之前透過 ID 無法做到的特殊聚合,現在把資料打寬,都可以進行視覺化的一些分析和展示了。

51.jpg

52.jpg

除此之外,對於常見問題,我們支援預先配置結論模型。當運維人員實時查詢微觀會話時,直接為他們給出結論。

53.jpg

得到結論後,我們就可以從更高的角度,觀察和統計整個業務環境的宏觀情況了,甚至可以進行實時的業務環境監控。從而提高故障的發現率、預警率、預警的準確率以及整個運維人力的能效。並且透過視覺化的展示可以使我們的風控平臺更準確的提供服務。

發展歷程與展望未來

54.jpg

早在 2017 年我們就對實時計算開始調研了,並在 2018 年形成了雙向發展的規劃,分別是平臺化和 SDK 手腳架的改造,經過多層的迭代,最終形成我們的一站式運維平臺。

55.jpg

隨著平臺和 SDK 的發展,我們的實時業務線也越來越廣泛。比如從最早的日誌分析監控,到通用的解析 ETL,到使用者畫像,到複雜的關聯分析,再到如今的實時風控平臺,我們也是在實時領域越走越遠,這都是 Flink 給我們帶來的變革。

未來我們希望,可以實時風控平臺可以支援更多的功能。比如我們希望支援用 Flink-SQL 即席查詢風控結果;使用者反饋驅動的風控模型修正;結合 Flink-ML 挖掘更深層次資料價值。

相關文章