微信遊戲推薦系統大揭祕

作者:boxianlai,騰訊 WXG 應用研究員

這篇文章整理於 2020 年 12 月 31 號在騰訊 WXG T 族開放技分享材料,分享內容是我們在搭建一套適合微信遊戲業務特色推薦系統過程中的設計方案和實踐經驗。這套系統從 18 年底開始設計 19 年初開發完成,現在已經在業務上運行了一年多,當前部門所有的推薦業務都已經應用上這套能力,包括所有精品 app 遊戲分發和遊戲相關的內容推薦、幾萬款小遊戲分發,服務着幾億微信遊戲玩家。在實際業務應用中,它切實滿足了很多業務對推薦的訴求,同時在業務核心指標上有了不錯的提升,下面是最近一段時間三個不同類型應用場景:小遊戲推薦、遊戲精細化運營挖掘、定向分享收到的業務產品同學的反饋,沒有商業互吹,都是真實對業務指標有提升。

我們在搭建過程中很多設計思想和實踐經驗相信也對其他 BG 的同學有借鑑價值,所以把此次分享內容整理成了一篇文章,希望對大家有一些幫助。

1、業務和項目背景介紹

微信增值業務部當前核心業務是遊戲,也就是在微信場景下連接遊戲玩家與遊戲,同時給玩家提供豐富的遊戲服務,比如攻略、戰績、視頻、直播等內容,王者週報、和平週報、羣排行榜、禮包等服務,另外還爲玩家提供建連的渠道,玩家可以在遊戲中心、遊戲圈裏面找到有共同興趣,志同道合的小夥伴,一起玩更精彩;說了那麼多,用一句話概括我們的遊戲業務就是:在微信場景下,幫助遊戲玩家找到感興趣的好遊戲,並且讓玩家們遊戲玩得更好,玩得更開心。

從上圖列舉的推薦場景可以看出,我們推薦系統也是圍繞這個方向來落地應用的,在幫助玩家找到好遊戲方面我們有精品 app 遊戲分發、小遊戲分發場景以及優化用戶通過搜索找到目標遊戲的場景;遊戲服務方面我們有視頻流、圖文流、直播流等內容推薦場景;在玩家們建連方面我們有玩家關注推薦、遊戲 kol 推薦、玩家廣場等產品。在上述各種類型的推薦場景之下,每個場景又會有各種各樣的業務目標,比如精品 app 遊戲除了下載啓動,還有新游上線前預約推廣,即需要找到對遊戲 ip 感興趣的潛在用戶,提升預約率;而小遊戲除了啓動註冊目標之外,同時小遊戲還有自己的商業化目標,需要預估商業價值和以流量 roi 爲優化目標的場景。而對於遊戲內容除了點擊轉換這個目標之外,還有視頻完成度、下翻率、播放時長、人均 vv 等目標。

事實上,上面列舉的場景只是我們衆多推薦場景中的一部分,從我們推薦系統管理端來看,我們已經建立 100 + 場景模型(一個 taskgroup 對應一個場景接口)。但現實矛盾點是我們只有四個推薦算法同學對接業務,負責的後臺也只有一個同學;針對這個矛盾點,我跟後臺同學討論一個理想的推薦場景的開發流程,希望把開發過程儘可能配置化,低代碼化,如上圖右邊部分,算法同學只需要開發場景相關的樣本和特徵,並將特徵表和樣本表配置到推薦管理平臺,在管理平臺上選擇合適的算法並配置參數,提交一個離線訓練任務,完成後將模型文件和推薦池子相關 hdfs 路徑配置到管理平臺分發到現網機器上;然後在實驗系統 xlab 上配置實驗,將實驗參數配置到統一推薦管理平臺上對應的場景接口(taskgroup)參數中,打通場景接口和實驗系統流量分配邏輯,最後把場景接口對應的 taskgroup 名字給到業務後臺同學,業務後臺同學根據這個名字調用統一的推薦接口,獲取推薦打分接口,完成一個場景的推薦開發。爲了達到上述的效果,我們設計了推薦系統的整體架構:

主要包括四個部分,離線機器學習平臺、統一推薦管理平臺、在線推薦引擎以及周邊系統;

Ø 離線機器學習平臺

模塊的核心功能是負責離線數據處理,包括特徵、畫像開發、場景樣本開發、特徵工程等相關工作;也負責離線模型訓練、離線與線上數據交互、批量打分等等。

Ø 統一推薦管理平臺

推薦管理平臺是推薦算法開發同學日常工作中使用最多的模塊,配置算法、開發特徵、配置模型、數據分發、定義推薦系統執行 DAG 圖、接口 debug、線上推薦問題排查等等,可以說推薦系統涉及到的工作都在這個平臺上完成。

Ø 在線推薦引擎

在線推薦系統負責提供實時接口服務,包括三個核心部分:用戶特徵模塊、推薦執行引擎、共享內存模塊;

用戶特徵模塊: 存儲用戶畫像和用戶行爲數據,起初我們使用 strkv 來存儲,根據數據更新週期分爲實時特徵、小時級特徵、天級特徵、月級特徵;但是月級和天級用戶量非常大,上線需要十幾個小時,今年統一切到了 featurekv。featurekv 寫速度要遠快於 strkv,但當時還不支持線上實時寫入,所以實時特徵我們還是用 strkv。

推薦執行引擎: 負責執行線上推薦邏輯調用,包括接收業務請求,拉去特徵,拼接預測樣本,調用算法模塊,完成推薦打分;其中核心模塊是 controller,它負責解析和執行算法同學定義的 DAG 執行圖(我們把推薦的執行邏輯定義爲一個 DAG 圖);還有算法模塊負責具體算法實現,每個算法實現是 controller 可調度執行的最小單元(除了機器學習算法實現之外,我們把一些常用的業務邏輯,比如混排、過濾邏輯等也封裝成這樣的執行單元,也就是後文提到的 stage)。

共享內存模塊: 線上預測的時候,同一個接口不同用戶請求推薦系統都會用到同一份 item 特徵,模型文件,特徵編碼文件,推薦池子,這種類型數據常駐內存可以減少單次請求耗時,所以後臺同學開發了管理這些數據的共享內存模塊,結合架構部文件分發工具,算法同學可以指定文件 hdfs 路徑,文件分發工具將文件分發到所有線上機器,共享內存模塊檢測到數據版本更新,將最新數據加載內存,完成線上數據更新。

Ø 周邊系統

除了上述推薦系統運行相關的模塊之外,還需要實驗系統支持算法同學迭代場景模型和實時監控系統可以觀測到算法上線之後的效果,線上問題的快速定位。

實驗系統: 我們使用架構部和基礎產品部提供的 xlab 實驗系統,在推薦系統 controller 模塊部署實驗系統代理,算法同學在 xlab 上配置完實驗之後,將實驗系統參數配置到推薦接口中,就可以打通實驗系統流量分配和推薦系統。

實時監控系統: 實時數據分析之一塊,我們部門搭建了 Druid 實時數據分析系統,支持實時數據監控和效果可視化,整體流程後面會講到。

爲了實現上述推薦系統整體架構,我們前期做了大量的調研,邀請了公司內外團隊過來分享,詳細對比了各個解決方案,對推薦系統各模塊技術選型以及公共組件等都做了比較詳細對比,下面是我們構建整套系統技術選型和對應的組件:

機器學習方面,傳統機器學習我們基於 spark 搭建模型訓練 pipeline,而深度學習使用 tensorflow,增量更新模型我們使用 flink 來實現,涉及向量檢索召回服務方面,我們搭建了 faiss 服務,實時數據分析我們選擇了 druid。

配置和存儲方面,我們使用 pg 庫存儲離線數據處理相關的所有配置,使用 mysql 存儲與線上相關所有配置,而 hdfs 是我們數據中轉站。

推薦引擎方面,我們基於微信內部的 svrkit 框架搭建的一套 c++ 推薦服務。

實際搭建過程中發現很多功能模塊公司內兄弟部門都有非常好的實現,我們直接拿來主義,比如調度方面直接使用 telsa,實時計算方面直接用 Oceanus 工具,深度學習可以直接使用 spark-fuel 和 yard,存儲這一塊架構部同學提供了文件分發工具、featurekv、strkv 等。深度學習線上應用上,我們直接使用架構部封裝的 HIE(hybrid_inference_engine)有了這些組件大大提升了我們搭建和維護這套系統的效率,在這裏也對負責相關組件的同學表示感謝。

除了工具調研之外,我們還邀請了當時在推薦系統方向做得比較好的團隊過來分享經驗,包括公司內的神盾、看一看、無量推薦系統團隊,也邀請外部公司的微博團隊。希望從這些團隊實踐經驗中吸取養分,找到適合微信增值業務特點的解決方案。事實上,這些經驗幫我們少走了很多彎路,我們的解決方案在業務適配方面做得還不錯,在應用過程中功能沒有大的改動,後續也只是在上面生長出更多能力。所以也是這次寫這篇文章的目的,希望我們的實踐經驗,可以給大家帶來一些啓發。接下來會詳細介紹各個模塊實現細節。

2、離線機器學習平臺設計

上面介紹整體架構提到離線平臺核心工作包括,數據 ETL、特徵開發、樣本開發、特徵工程、模型訓練和預測、線上和離線數據打通等工作。其中特徵工程、模型訓練和預測、線上線下數據打通是任何一個場景建模都是需要做得工作,離線平臺通過工具化和流程化實現通用組件,避免重複工作。而數據 ETL、特徵開發、樣本開發是與業務場景強綁定,很難通過自動化方式實現,需要算法同學結合業務目標定製化實現,離線平臺提供基礎工具,幫助場景建模同學提高開發效率,下圖是離線平臺實現邏輯:

從下往上分別包括底層數據源接口,數據挖掘基礎工具庫,這兩部分主要幫助算法同學提升日常數據開發效率;往上是場景建模過程中核心三個組件,算法庫、特徵工程、業務樣本模塊;算法庫包含兩個部分,一個部分是基於 spark 實現,另一部分是基於 tensorflow 實現,這裏沒有使用 telsa 訓練組件,而是自己做了二次開發,主要原因是離線算法需要和線上引擎數據協議進行打通,比如我們需要將訓練好的模型和相關文件封裝到一個 pb 文件中,直接部署到現網機器可以拉去到的地方,不需要每個算法同學都要單獨實現數據部署邏輯;另外我們希望模型訓練可以跟數據處理邏輯無縫銜接,減少數據中轉。

特徵工程主要包括特徵開發、特徵處理、特徵評估等涉及到特徵相關的操作都封裝到單獨模塊中,方便算法同學對特徵進行單獨分析和測試;涉及到樣本處理工作我們放在樣本模塊中完成,包括樣本採樣邏輯,不同目標樣本處理,還有一些小流量場景需要多週期樣本處理等等。再往上實現了基於 DAG 圖的機器學習 pipeline,目的是將場景整個建模過程通過有向無環圖的方式管理起來,數據讀取邏輯被定義爲節點,數據操作邏輯被定義爲邊,節點只關心從物理存儲中拉去數據;邊主要是數據處理邏輯定義,不關心數據來源;這樣數據讀取和數據操作進行節藕。我們根據定義的邊和節點,可以組合出不同的 DAG,比如模型訓練、模型預測、號碼包生成、外部接口等等,供上面應用層調用。最上面是我們推薦系統管理端,我們希望與模型相關的工作都可以通過配置化方式進行。下面詳細介紹核心模塊實現細節:

Ø 底層基礎庫

基礎庫提供了開發過程中常用基礎工具,目標是幫助開發同學提升日常數據處理的效率,主要包括 tdw 操作接口封裝和通用工具封裝,如下圖所示:

tdw 提供原始數據接口,在實際業務開發過程中並沒有那麼友好,比如 spark 讀取 tdw 表數據,需要先配置 spark 程序入口環境,初始化 tdw tool 工具,處理表分區,然後再調用表讀取 api 進行讀取;其中前面步驟都是通用重複的工作,所以在平臺提供的 api 基礎上,進行二次封裝。在開發過程中,開發同學不需要關心環境變量和參數配置,直接初始化封裝的類,然後使用簡易接口進行表操作和表處理,提升工作效率。

通用工具,其實是把日常工作中都會用到的能力進行封裝,比如日期處理,日誌處理,編碼解碼以及類型轉換等。以前這些小工具都散落在各個地方,現在有協作工程,能力也慢慢積累起來了。另外與業務相關的工具我們也做了收攏,比如遊 ID 間相互轉化,遊戲品類 ID 和名稱相互轉化等等,這些業務上通用的能力我們也集成到基礎庫中,不需要每個同學重複實現。

Ø 算法庫設計

算法庫設計的核心是擴展性,一方面可以快速便捷擴展新的算法進來。在實際業務應用中,我們不需要那些花裏胡哨,很難落地應用的算法,需要的是那些能解決業務問題,可以快速與線上打通,並驗證效果的算法;另外一方面算法庫可以便捷的集成外部團隊的能力,將外部專業團隊成熟的能力快速應用到業務中,解決業務問題。出於上述考慮,也吸收公司內其他團隊經驗,設計了下面這個架構:

算法基類定義了算法基本操作,並將算法通用操作提前實現,比如模型參數初始化,模型部署操作等,其他算法直接繼承即可;然後分別定義了分類算法、聚類算法、相似度算法、深度學習類算法還有 nlp 相關的算法抽象操作。最後是具體算法實例的實現,分類算法實現了常用的如 LR、FM、RF、xgb 等;聚類有 kmean;相似度算法實現了三種類型相似,基於內容、基於用戶行爲序列、這二種相似算法都是將 item 或者 user 進行向量化,然後通過向量內積計算 item 或者 user 之間的相似度。

在遊戲中心視頻相關推薦場景實驗數據來看,基於內容向量化效果穩定性最好,推薦出來的內容基本符合認知,比如魯班七號的視頻,推薦出來都是與魯班或者射手相關的內容。在深度學習方面核心是打通數據流程,訓練和線上預測都依託 tensorflow 和 tf-serving 通用框架,接下來也會詳細介紹整體流程。對於 nlp 相關算法,主要是基於 hanNLP 來實現了包括常用的分詞、實體識別、文本分類等功能。最後通過工廠方法實現對應算法實例路由。

Ø 深度學習流程設計

2019 年下半年遊戲中心很多場景對混排和多目標優化能力訴求越來越強,包括內容 feeds 流、遊戲 tab feeds 流裏面精品遊戲、小遊戲等不同類型不同目標的混排。最開始我們採用的方案是增加規則混排邏輯,比如按比例混排,給定概率混排,根據模型打分分數運算混排等。後來還採用雙層排序邏輯:先預估用戶對不同類型的偏好分佈,再根據這個偏好分佈從不同類型的已排序好的列表中選擇對應的 item,生成最終的排序列表。這些方式可以滿足業務需求,但是指標沒有顯著提升,核心原因是層與層之間是割裂的,沒有作爲一個整體去優化,而業界成熟的做法是把不同層通過網絡結構結合在一起,爲此我們在當前能力的基礎上,開發了一套流程來支持 nn 能力。

如上圖所示,深度學習訓練流程是在原有的機器學習平臺的基礎上,通過集成外部能力來實現的。根據不同的業務需求,我們實現了兩條不同的訓練路徑,一個是在 tesla 平臺上,基於 spark-fuel 來實現,應用於線上業務;另外一個是基於數據中心笛卡爾系統 + yard 來實現,應用於需要推薦、圖像、文本挖掘等能力的業務。我們主要開發工作包括:在算法庫中增加一個算法模版,這個模版的工作是把業務訓練數據生成下層對接系統可以處理的格式(當前推薦業務使用 libsvm 格式),並將生成好的數據持久化到 hdfs 上;然後基於 tensorflow 實現網絡結構、數據讀取模塊、以及模型持久化模塊;最後把模型推送到線上,而線上 tensorflow-serving 是後臺同學基於架構部 HIE 實現的。需要注意的是在線上使用的時候,要保證特徵編碼文件與模型文件保持原子更新。有了這套訓練和線上預測框架之後,算法同學可以發揮的空間就更大了,除了推薦算法上落地應用外,我們遊戲直播裏面的英雄識別、遊戲人生漫罵識別等涉及圖像、文本相關的服務也都應用這一套能力,具體細節這裏就不展開講。

Ø 頁面配置化設計方案

下圖是我們現網統一推薦管理端頁面,包含兩個大模塊:推薦系統和數據資源管理。推薦系統包括我們特徵管理、離線模型訓練配置、線上推薦接口執行流(json 表徵的 DAG 圖)配置、還有就是推薦接口調試和問題排查的 debug 工具。數據資源管理主要涉及到離線數據和線上數據打通部分,包括用戶特徵導入 kv 和 item 特徵、推薦池子、模型文件等推送到現網機器的定時分發任務配置。

統一推薦管理端把現網推薦開發涉及到的工作都包含進來了,使得離線數據挖掘和線上業務上線推薦模型代碼最小化,大大提升了場景算法迭代效率。管理端設計上,如下圖所示我們主要拆解成離線和在線兩個部分:

日程表  描述已自動生成

離線部分對接的是離線計算平臺和離線數據部署模塊,通過配置相關的參數,完成場景數據開發、模型訓練、數據上線的整個過程。算法同學在離線部分頁面的配置信息,我們會存儲在 tpg 庫中。離線訓練模型的時候,通過指定場景配置的算法 ID,就可以檢索到存儲在 tpg 表中算法 ID 對應的算法相關的參數信息,並將它們封裝到算法上下文中(algorithmContext),然後根據配置信息拉取數據生成訓練樣本,調用算法同學指定的算法訓練模型,輸出評估指標,最後將模型部署在對應路徑下,完成離線訓練。離線數據部署配置背後隱含了兩個部分工作,第一個是離線特徵出庫有一個 dataDeploy 模塊,會根據算法配置信息上的上線狀態,拉取需要上線的特徵,並將這些特徵序列化成定義好的 pb 格式,寫入 hdfs 中。另外一個是後臺同學開發的數據 upload 工具,根據算法同學配置的數據相關信息(信息存儲在後臺 mysql 中)利用 Hadoop 客戶端從 hdfs 路徑下拉去數據,定時導入到現網 kv(featurekv)或者推送到現網機器。這部分工作對於場景算法開發同學來時是透明的,他只需要完成頁面配置即可。

在線部分對接的是現網數據和推薦引擎,包括現網模塊配置、stage 配置、taskgroup 配置、task 配置、場景相關的資源配置。這些配置裏面的每一條記錄都會有一個名字標識,比如線上實現的每一個可執行算法單元,會在 stage 配置頁面上使用唯一 name 進行標識,後面應用的時候通過這個 name 就可以調用這個算法單元;現網場景數據也是一樣,配置的每個數據資源也會對應唯一 name,比如小遊戲推薦池子對應一個 name A,精品遊戲推薦池子對應的 name B。一個場景有了資源和需要執行算法單元之後,就可以配置一個推薦接口(taskgroup), 如下圖所示:

一個推薦接口(taskgroup)下面可以配置多個執行邏輯(task,可以理解成是一個接口下面會有多個實驗)如下圖所示,遊戲中心首頁直播推薦接口,配置了兩個 task:

每個 task 對應着一個 json 表徵的 DAG 圖,它包括:執行流程是怎樣(使用哪些算法,執行邏輯是串行還是並行),每個算法使用哪些數據(特徵、池子等,給定前面配置的資源 name 即可)這個圖在一開始設計的時候是拖拽的方式來添加和刪除圖節點,目前還是算法同學自己寫 json 串。如下圖是一個 task 配置:

所有這些線上配置信息會存儲在現網 mysql 中,線上執行模塊可以直接通過 name 訪問對應的文件。完成上面配置之後,算法同學就可以在頁面對單個 task 進行 debug,滿足上線標準之後(排序是否正常、耗時是否滿足線上標準等),就可以把 taskgroup name 給到業務後臺同學,完成上線。

從上面看出,因爲我們通過頁面配置打通了從離線到線上的全流程,所以負責流程中每個環節的同學工作效率都有很大提升。

Ø 平臺能力拓展

離線平臺能力我們希望打造成部門底層通用的基礎能力,不僅僅在推薦業務上使用,還能拓展到畫像、數據分析、安全以及所有跟機器學習相關的業務上。事實上圍繞着這個平臺,我們也做了很多能力升級和拓展,比如最近在小遊戲,基於平臺能力,我們搭建了提供給小遊戲開發者的自助精準用戶挖掘能力和廣告 rta 能力,幫助他們提升用戶獲取能力和降低用戶獲取成本。

img

從上圖可以看出,以前開發者買量大多數只能針對包進行出價和投放;但現在在小遊戲開發者管理端上,通過我們這套能力在 pv 維度上進行過濾和出價,對於一些用戶過濾或者降低出價,對於其他可以用更高價獲取,提升整體買量 roi。對於平臺來說,以前爲了幫助小遊戲開發者更好的買量,我們需要投入專人挖掘精準號碼包,但有了這套系統之後,我們的人力開始往能力建設遷移,後面希望我們建設好的一個能力,開發者可以通過這個平臺第一時間使用到。下面簡單提一下號碼包平臺設計思路,上面推薦管理端配置信息我們都是用戶固定表格式來存儲,但是號碼包平臺考慮到平臺頁面靈活性(未來配置信息變動大),我們方案是後臺同學將配置生成 json 串,然後通過參數的方式傳入給平臺開發者提交挖包任務之後,直接通過 tesla api 調度挖包任務,完成挖包操作,整個流程都是開發者自助完成。這套系統已經在穩定運行了一個多月,有很多小遊戲開發者再用這些能力,而投放 roi 上也有明顯提升,符合預期。後面有更多實踐經驗我們在詳細聊聊這一塊的工作。

3、推薦引擎設計

業界大部分推薦團隊一般包含一個算法組和引擎工程組,算法組負責場景離線建模和數據相關的工作;引擎工程組負責線上工程實現,包括算法模塊開發、線上數據流處理以及系統調度相關工作。但是我們團隊沒有獨立引擎組,爲了保證未來推薦系統能夠適應業務快速迭代,和後臺同學商量我們推薦引擎設計上應該與其他推薦團隊有所差異,首先在分工上後臺同學負責整體框架的開發,同時把基礎能力接口化,比如讀取用戶特徵、讀取模型文件等,然後單獨出一個算法模塊給算法同學實現模型線上預測打分邏輯,也就是利用這些基礎接口,算法同學可以完成數據讀取、數據處理到最終模型預測開發。這樣分工一個明顯的好處是算法同學很清楚線上鏈路,當業務場景出現 badcase 時,可以快速定位到問題,同時也減少了很多溝通成本。後續業務需要使用到某些算法的時候,算法同學可以利用這些基礎能力完成線上開發,當然一些很難的算法實現,我們也會請求後臺同學支持。在實際應用中,這樣的分工讓我們可以快速響應業務需求,特別是業務邏輯相關的,比如加權、過濾、混排等。

另外一方面,我們很難像其他推薦團隊一樣有專門同學單獨負責推薦的單個環節,比如召回、粗排、精排、混排,所以在引擎架構設計需要淡化這些層級關係,所以我們定義了 action、node、stage 這些算子。其中 stage 表示可以調度的最小單元;node 是由 stage 組成的並行執行的最小單元;action 是由 node 組成的串行之行的最小單元。另外我們統一這些算子的輸入輸出,使得這些算子可以相互嵌套。通過這樣的設計,算法同學可以根據業務的需求,自由組合這些基本單元,來達到召回、粗排、精排、混排的推薦架構。而算法使用上也比固定層級的設計要更加靈活,比如 FM 算法可以作爲召回、粗排層或者精排、混排層,算法同學可以根據場景特點進行自由組合搭配。整個推薦引擎架構如下圖所示:

社交網絡的手機截圖  描述已自動生成

當一個用戶請求一個業務時,推薦引擎會根據實驗系統命中情況,確定用戶命中哪個策略,拿到這個策略對應的 task 名字,然後根據 task 名字可以在 mysql 中獲取 task 對應的 DAG 執行圖,controller 通過解析並執行這個 DAG 圖,得到推薦結果,返回給業務後臺。下圖是後臺同學在實現上函數邏輯調用關係,這裏就不細講,有興趣的同學可以找我們這邊後臺同學瞭解實現細節。

線上部分算法同學涉及的工作主要是兩塊,一個是線上算法實現;另外一個是數據結構設計和對應的數據處理。首先看一下線上算法實現部分,從上面架構也可以看出,線上最小執行單元是 stage,它本質上就是一個 svrkit RPC 接口,其實也就是一個算法或者策略的實現,比如我們現在現網有 LR、FM、xgb、tagRecall、tf、加權混排、根據概率分佈混排等 stage。一個 stage 內部邏輯如下圖所示:

其中 stageMeta 是算法同學在統一推薦管理端在配置 task 執行 DAG 圖的時候需要提供的,表示這個 stage 執行過程中使用哪些數據,執行參數是怎樣的。而物理維度上的數據是通過架構部的文件分發系統,從 hdfs 或 ceph 拉取並分發到現網機器磁盤,然後本地資源管理模塊會定期 check 資源版本,有新版更新會解析並加載到內存中,供 stage 使用。爲了滿足 stage 之間可以相互組合,我們統一了 stage 的輸入和輸出,輸入是一個 repeated,它可以是業務請求 stage 時帶入的 data,也可以是上一個 stage 或者上層並行執行的多個 stage 的結果。

這裏提到 data 結構可以理解爲就是候選列表以及列表內每個 item 所帶的參數,比如上層打分、來源、權重等。而當前 stage 輸出也是一個 data,可以作爲結果反饋給後臺,也可以作爲下一層 stage 的輸入。對於一個 stage 內部包含兩個部分,一個模型加載和預測部分;另外一個是根據 stagemeta 信息和輸入的候選打分列表生成模型打分數據格式,然後將這個數據餵給模型打分,生成結果數據。

算法同學涉及到的另外一個部分工作是數據結構設計和數據處理,下圖列舉了我們在線上使用的核心數據結構,包括特徵結構、模型結構、特徵交叉結構。爲了保證線上線下一致性,我們都採用 protobuf 來表徵。對於特徵我們採用了雙層 map 結構來存儲,第一層是 featureDataSet 單個 item / 單個用戶所擁有的特徵,map 的 key 是特徵名字,value 是內層 map featureDataPairs,它是該特徵的取值。比如遊戲偏好這個特徵,內層取值可能是 rpg、moba 或許休閒等。單維度特徵相關信息用 featureData 存儲。

對於特徵交叉結構,我們使用二叉樹來存儲交叉信息,葉子結點表示交叉子特徵,內節點表示交叉算子,通過這樣的設計,我們就可以進行二階交叉、三階交叉…..,n 階交叉。離線模型使用的交叉特徵信息是與模型綁定在一個 pb 結構裏面進行出庫的,保證模型和交叉文件原子性。類似的還有特徵名字和 index 之間的映射關係,也需要與模型 pb 進行原子更新,當然這是很細節的實現部分了。對於圖中的模型結構一部分是單個算法的定義,把訓練好的模型信息封裝到 pb 裏面。另外需要把剛纔提到涉及到原子更新的信息在模型持久化的時候,部署在一個 pb 文件中,這樣做的目的是保證線上線下數據一致,這裏也就是前面提到爲什麼說離線沒有直接用 tesla 或者其他平臺提供訓練能力,而是自己實現裏面的訓練邏輯的原因。

4、推薦系統實時化方案

19 年初的時候,部門後臺同學搭建了一套基於 Oceanus+Druid 實時監控系統,幫助業務可以實時查看和監控業務指標和服務性能指標。同時把還協議接入、數據清洗、協議轉發 kafka 等各個環節進行了封裝。推薦系統實時化也是在延展,一方面監控推薦場景的實驗實時效果;另外一方面在這基礎上,增加實時特徵和模型增量更新的能力,整體流程如下圖所示:

在實時流配置模塊,可以根據協議 ID 對協議數據進行清洗和篩選出場景對應的數據(Oceanus 每個核只能處理 1W/s 行,數據太多容易阻塞,所以清洗和篩選需要前置)然後新建一個 kafka 的 topic 並關聯協議數據。後面的算法大部分的開發工作都是在 oceanus 上完成的。對於實時特徵,我們定義了實時特徵的通用結構,在 Oceanus 上完成特徵邏輯的開發後臺,item 特徵會落到 hdfs 上,通過文件分發系統分發到現網機器上;用戶特徵則是再寫入到 kafka,經過後臺一個 svrkit 服務將特徵寫入現網 kv。增量學習的流程是在 Oceanus 上完成樣本邏輯開發之後,再將樣本數據寫入到 kafka,後臺有一個 svrkit 服務讀取樣本數據,並調用現網預測部分的數據處理模塊,根據樣本信息生成 libsvn 格式數據寫入到 kafka,然後再回到 oceanus 上完成模型訓練、評估和部署。

5、遇到的問題與挑戰

前面已經把搭建推薦系統的整體流程介紹完成,下面介紹我們在實際業務應用過程中遇到的幾個問題和挑戰以及我們的應對方案。首先是數據管理,從離線建模到模型部署上線的各個環節都涉及到離線與線上的數據交互,一開始我們是每個場景算法開發同學各自維護各個場景數據上傳腳本,並通過 crontab 定時導入到線上。隨着接入推薦系統的場景越來越多,這種方式很快就遇到瓶頸了:維護成本高、數據分散、數據質量很難保證、線上出現 badcase 定位週期長等等。爲了解決這個問題,我們從兩個方面進行着手,首先與線上交互的數據統一放到一起管理,使用頁面配置代替腳步;另外一塊是把特徵相關的數據上線使用 dataDeploy 模塊進行統一出庫和上線,並提供數據查詢工具,可以快速查到現網數據,讓算法法同學確認數據是否正常上線。

第二個挑戰是我們業務場景很多,負責場景建模的就固定幾個同學,隨着接入推薦系統場景越來越多,單個同學的負擔也越來越重,特別是花在 badcase 定位和異常排查時間非常多;爲了緩解這個問題,我們梳理了推薦整體流程,把重點環節監控起來,同時結合實時監控,幫助我們提前感知到線上異常。當發現異常時,結合 ilog 系統快速定位到問題發生的場景和原因。另外一塊我們搭建了推薦系統的白板系統,如下圖所示,通過給定的 taskgroup 和對應 task,把線上打分流程可視化出來,同時展示出打分過程中使用的特徵細節。

運維成本高還有另外一個非常大的挑戰是我們活動資源推送帶來瞬間流量峯值。這個瞬間流量峯值,直接把推薦系統搞掛了,自動擴容還沒啓動,機器資源就跑滿了,導致大量的邏輯失敗。印象最深的是 19 年這個系統第一次經受春節考驗,大量紅點資源推送,導致大量用戶湧入遊戲中心,把推薦系統撐掛了,好在後臺有備選 list,後臺同學手動把部分流量切到默認 list,纔沒有影響到現網用戶。這裏也非常感謝團隊,沒有責備我們,而是在春節期間帶領我們尋找解決方案。當前我們的做法根據流量自動分級處理,第一級是正常推薦;第二級是部署另外一個與推薦系統並行的模塊,如果推薦系統模塊掛了,自動切到這個模塊,執行耗資源少的兜底邏輯;第三級是所有模塊都失敗了,切到後臺 list。下圖所示的 ID=453 的 task 就是這個接口配置的兜底邏輯。另外一方面對耗時和耗資源代碼進行優化。經過這些優化之後,系統再也沒有出現大面積失敗的情況了。

第三個是所有推薦系統都會面臨的耗時問題。開始只接入 IEG 精品遊戲推薦場景,因爲 item 個數少,沒有耗時問題。但是隨着小遊戲分發和內容分發場景的上線,耗時隨着 item 個數增加而增加。這裏我們的後臺同學把線上打分整個流程做了耗時評估,發現數據處理佔了總體耗時的 70%,進一步細化分析則發現核心問題是在涉及數據結構的時候埋下了一個隱患,pb 裏面 map 結構使用 string key 性能非常差,後面改成 int64;同時對特徵拼接流程進行優化,優先拼接好用戶特徵,再拼接上 item 和交叉特徵,而不是單個 uin-item pair 對進行拼接,經過這些優化,耗時明顯改善。另外對應多 item 和多特徵的場景,通過增加粗排層,在性能和準確度上進行權衡。

上面把我們推薦系統從調研、設計、搭建再到運維整個過程介紹完了,希望能給大家帶來一些啓發。

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