得物自研DGraph4.0推薦核心引擎升級(jí)之路
一、前言
二、架構(gòu)升級(jí)
1. 垂直拆分業(yè)務(wù)集群支持
2. 分布式能力支持
三、性能優(yōu)化
1. 算子執(zhí)行框架優(yōu)化
2. 傳輸協(xié)議編碼解碼優(yōu)化
四、用戶(hù)體驗(yàn)優(yōu)化
1. DAG圖調(diào)試功能優(yōu)化
2. DAG圖支持TimeLine分析
3. DAG圖支持動(dòng)態(tài)子圖
五、展望未來(lái)
一、前言
DGraph是得物自主研發(fā)的新一代推薦系統(tǒng)核心引擎,基于C++語(yǔ)言構(gòu)建,自2021年啟動(dòng)以來(lái),經(jīng)過(guò)持續(xù)迭代已全面支撐得物社區(qū)內(nèi)容分發(fā)、電商交易等核心業(yè)務(wù)的推薦場(chǎng)景。DGraph在推薦鏈路中主要承擔(dān)數(shù)據(jù)海選和粗排序功能,為上層精排提供高質(zhì)量候選集。
核心技術(shù)特性:
- 索引層 - 支持KV(鍵值)、KVV(鍵-多值)、INVERT(倒排)、DENSE-KV(稠密鍵值)等。索引存儲(chǔ)支持磁盤(pán) & 內(nèi)存兩種模式,在預(yù)發(fā)等延遲壓力低場(chǎng)景,通過(guò)磁盤(pán)索引使用低規(guī)格服務(wù)器提供基本服務(wù)。線上場(chǎng)景使用內(nèi)存索引保證服務(wù)穩(wěn)定性,提供毫秒級(jí)延遲響應(yīng)。索引更新支持雙buff熱更新【內(nèi)存足夠】、服務(wù)下線滾動(dòng)更新【內(nèi)存受限】、Kafka流式數(shù)據(jù)實(shí)時(shí)更新等三種模式。
- 查詢(xún)層 - 支持向量檢索IVF & HNSW、鍵值(KV)查詢(xún)、倒排檢索、X2I關(guān)聯(lián)查詢(xún)、圖查詢(xún)。對(duì)外提供JavaSDK & C++ SDK。
系統(tǒng)依賴(lài)架構(gòu):
- 索引全生命周期管理由得物索引平臺(tái)DIP統(tǒng)一管控。
- 服務(wù)發(fā)現(xiàn)基于ZooKeeper(zk)。
- 集群資源調(diào)度基于得物容器平臺(tái),目前已經(jīng)支持HPA。
服務(wù)規(guī)模:
- 目前在線100+集群,2024年雙11在線突破了100W QPS。
本文主要介紹DGraph系統(tǒng)在2024年的一些重要改進(jìn)點(diǎn)。主要包括兩次架構(gòu)調(diào)整 + 性能優(yōu)化 + 用戶(hù)體驗(yàn)提升方面的一些工作。
二、架構(gòu)升級(jí)
垂直拆分業(yè)務(wù)集群支持
在2023年前,DGraph系統(tǒng)始終采用單一集群架構(gòu)提供服務(wù)。該架構(gòu)模式在平臺(tái)發(fā)展初期展現(xiàn)出良好的經(jīng)濟(jì)性和運(yùn)維便利性,但隨著業(yè)務(wù)規(guī)模擴(kuò)張,單集群架構(gòu)在系統(tǒng)層面逐漸顯露出三重剛性約束:
- 存儲(chǔ)容量瓶頸 - 單節(jié)點(diǎn)內(nèi)存上限導(dǎo)致數(shù)據(jù)規(guī)模受限;
- 網(wǎng)絡(luò)帶寬瓶頸 - 單物理機(jī)Pod共享10Gbps帶寬,實(shí)際可用帶寬持續(xù)承壓,推薦引擎業(yè)務(wù)中部分核心集群200余張數(shù)據(jù)表(單表需20分鐘級(jí)更新)的實(shí)時(shí)處理需求已遭遇傳輸瓶頸;
- 計(jì)算能力瓶頸 - 單實(shí)例最大64核的算力天花板,難以支撐復(fù)雜策略的快速迭代,核心場(chǎng)景響應(yīng)時(shí)效與算法復(fù)雜度形成顯著沖突;
- 穩(wěn)定性 - 大規(guī)格集群對(duì)于容器調(diào)度平臺(tái)不友好,在擴(kuò)容、集群故障、集群發(fā)布時(shí)耗時(shí)較久;基于得物平臺(tái)推薦數(shù)據(jù)量增長(zhǎng)和算法迭代需求,我們實(shí)施業(yè)務(wù)垂直拆分的多集群架構(gòu)升級(jí),通過(guò)資源解耦與負(fù)載分離,有效突破了單節(jié)點(diǎn)資源約束,為復(fù)雜算法策略的部署預(yù)留出充足的技術(shù)演進(jìn)空間。
系統(tǒng)改進(jìn)點(diǎn)是在DGraph中增加了訪問(wèn)了其他DGraph集群 & FeatureStore特征集群的能力(圖1)。為了成本考慮,我們復(fù)用了之前系統(tǒng)的傳輸協(xié)議flatbuffers,服務(wù)發(fā)現(xiàn)仍基于ZooKeeper。
圖 1 DGraph 訪問(wèn)架構(gòu)改進(jìn)
改造的難點(diǎn)在圖化集群!
目前推薦業(yè)務(wù)的核心場(chǎng)景都進(jìn)行了圖化改造,圖化查詢(xún)是把多路召回、打散、融合、粗排等策略打包到一個(gè)DAG圖中一次發(fā)送到DGraph,DGraph的算子調(diào)度模塊根據(jù)DAG的描述查詢(xún)索引數(shù)據(jù) & 執(zhí)行算子最終把結(jié)果返回給業(yè)務(wù)系統(tǒng),但這些DAG圖規(guī)模都很大,部分業(yè)務(wù)DAG圖涉及300+算子,因此如何在垂直拆分業(yè)務(wù)中把這些DAG圖拆分到不同的DGraph集群中是一個(gè)非常復(fù)雜的問(wèn)題,我們主要做了三方面改進(jìn):
- DAG管理 - 集群分主集群和從集群【多個(gè)】,DAG圖部署在存在主集群中,DIP平臺(tái)會(huì)分析DAG的拓步結(jié)構(gòu)并把屬于從集群的部分復(fù)制出來(lái)分發(fā)給從集群,為了保證DAG的一致性,只允許從主集群修改DAG圖;
- 集群劃分 - 通常按召回劃分,比如Embedding召回、X2I召回、實(shí)驗(yàn)召回可以分別部署在不同的集群,另外也可以把粗排等算力需求大的部分單獨(dú)放在一個(gè)集群,具體根據(jù)業(yè)務(wù)場(chǎng)景調(diào)整;
- 性能優(yōu)化 - 核心表多個(gè)集群存放,減少主集群和從集群間數(shù)據(jù)交換量。
圖 2 DGraph業(yè)務(wù)垂直拆分集群
分布式能力支持
垂直拆分集群,雖然把推薦N路召回分散到了M個(gè)集群,但是每個(gè)集群中每個(gè)表依然是全量。隨著得物業(yè)務(wù)的發(fā)展,擴(kuò)類(lèi)目、擴(kuò)商品,部分業(yè)務(wù)單表的數(shù)據(jù)量級(jí)已經(jīng)接近單集群的存儲(chǔ)瓶頸。因此需要DGraph中引入數(shù)據(jù)水平拆分的能力。
圖 3 DGraph 分布式集群架構(gòu)圖
在DGraph分布式架構(gòu)設(shè)計(jì)中,重點(diǎn)考慮了部署成本優(yōu)化與業(yè)務(wù)遷移工作量:
- 分布式集群采用【分片數(shù)2】×【雙活節(jié)點(diǎn)2】×【數(shù)據(jù)副本數(shù)2】的最小拓?fù)浣Y(jié)構(gòu),理論上需要8臺(tái)物理節(jié)點(diǎn)保障滾動(dòng)更新與異常容災(zāi)時(shí)的穩(wěn)定性。針對(duì)CPU負(fù)載較輕的場(chǎng)景,為避免獨(dú)立Proxy集群帶來(lái)的額外資源開(kāi)銷(xiāo),DGraph將Proxy模塊和DGraph引擎以對(duì)稱(chēng)架構(gòu)部署到所有節(jié)點(diǎn),通過(guò)本地優(yōu)先的智能路由策略(本地節(jié)點(diǎn)輪詢(xún)優(yōu)先于跨節(jié)點(diǎn)訪問(wèn))實(shí)現(xiàn)資源利用率與訪問(wèn)效率的平衡;
- 在業(yè)務(wù)兼容性方面,基礎(chǔ)查詢(xún)接口(KV檢索、倒排索引、X2I關(guān)聯(lián)查詢(xún))保持完全兼容以降低遷移成本,而DAG圖查詢(xún)需業(yè)務(wù)側(cè)在查詢(xún)鏈路中明確指定Proxy聚合算子的位置以發(fā)揮分布式性能優(yōu)勢(shì)。數(shù)據(jù)鏈路層面,通過(guò)DIP平臺(tái)實(shí)現(xiàn)索引無(wú)縫適配,支持DataWorks原有任務(wù)無(wú)需改造即可對(duì)接分布式集群,同時(shí)增量處理模塊內(nèi)置分片過(guò)濾機(jī)制,可直接復(fù)用現(xiàn)有Flink實(shí)時(shí)計(jì)算集群進(jìn)行數(shù)據(jù)同步。
三、性能優(yōu)化
算子執(zhí)行框架優(yōu)化
在DGraph中,基于DGraph DAG圖(參考圖9)的一次查詢(xún)就是圖查詢(xún),內(nèi)部簡(jiǎn)稱(chēng)graphSearch。在一個(gè)DAG圖中,每個(gè)節(jié)點(diǎn)都是一個(gè)算子(簡(jiǎn)稱(chēng)Op),算子通過(guò)有向邊連接其他算子,構(gòu)成一個(gè)有向無(wú)環(huán)圖,算子執(zhí)行引擎按DAG描述的關(guān)系選擇串行或者并發(fā)執(zhí)行所有算子,通過(guò)組合不同算子DAG圖能在推薦場(chǎng)景中靈活高效的完成各種復(fù)雜任務(wù)。
在實(shí)際應(yīng)用場(chǎng)景中受DAG圖規(guī)模 & 超時(shí)時(shí)間(需要控制在100ms內(nèi))限制,算子執(zhí)行框架的效率非常重要。在最開(kāi)始的版本中我們使用過(guò)Omp & 單隊(duì)列線程池,集群在CPU負(fù)載低于30%時(shí)表現(xiàn)尚可,但在集群CPU負(fù)載超過(guò)30%后,rt99表現(xiàn)糟糕。在降本增效的背景下,我們重點(diǎn)對(duì)算子執(zhí)行框架進(jìn)行了優(yōu)化,引入了更高效的線程池 & 減少了調(diào)度過(guò)程中鎖的使用。優(yōu)化后目前DGraph 在CPU壓力超過(guò)60%依然可以提供穩(wěn)定服務(wù)。
圖4 DGraph算子執(zhí)行框架優(yōu)化
線程池優(yōu)化:將原1:N 的線程池-隊(duì)列架構(gòu)調(diào)整為M:N 分組模式。具體實(shí)現(xiàn)為將N個(gè)工作線程劃分為M個(gè)執(zhí)行組(每組N/M線程),各組配備獨(dú)立任務(wù)隊(duì)列。任務(wù)提交采用輪詢(xún)分發(fā)機(jī)制至對(duì)應(yīng)組隊(duì)列,通過(guò)資源分區(qū)有效降低線程調(diào)度時(shí)的鎖競(jìng)爭(zhēng)強(qiáng)度。
調(diào)度器優(yōu)化:在DAG調(diào)度過(guò)程中存在兩個(gè)典型多寫(xiě)場(chǎng)景
- 前驅(qū)算子節(jié)點(diǎn)完成時(shí)需并行更新后繼節(jié)點(diǎn)標(biāo)記;
- DAG全局任務(wù)計(jì)數(shù)器歸零判斷。原方案通過(guò)全局鎖(Graph鎖+Node鎖)保障原子性,但在高負(fù)載場(chǎng)景引發(fā)顯著鎖競(jìng)爭(zhēng)開(kāi)銷(xiāo),影響線程執(zhí)行效率。經(jīng)分析發(fā)現(xiàn)這兩個(gè)狀態(tài)變更操作符合特定并發(fā)模式:所有寫(xiě)操作均為單調(diào)增減操作,因此可將鎖機(jī)制替換為原子變量操作。針對(duì)狀態(tài)標(biāo)記和任務(wù)計(jì)數(shù)場(chǎng)景,分別采用原子變量的FetchAdd和FetchSub指令即可實(shí)現(xiàn)無(wú)鎖化同步,無(wú)需引入CAS機(jī)制即滿(mǎn)足線程安全要求。
傳輸協(xié)議編碼解碼優(yōu)化
優(yōu)化JavaSDK - DGraph數(shù)據(jù)傳輸過(guò)程:在DGraph部分場(chǎng)景,由于請(qǐng)求引擎返回的數(shù)據(jù)量很大,解碼編碼耗時(shí)占整個(gè)請(qǐng)求20%以上。分析已有的解碼編碼模塊,引擎在編碼階段會(huì)把待傳輸數(shù)據(jù)編碼到一個(gè)FlatBuffer中,然后通過(guò)RPC協(xié)議發(fā)送到業(yè)務(wù)側(cè)的JavaSDK,SDK解碼FlatBuffer封裝成List<map> 返回給業(yè)務(wù)代碼,業(yè)務(wù)代碼再把List<map> 轉(zhuǎn)化成 List<業(yè)務(wù)Object>。過(guò)程中沒(méi)有并發(fā) & SDK側(cè)多了一層冗余轉(zhuǎn)換。
優(yōu)化方案如下:
- 串行編碼調(diào)整為根據(jù)文檔數(shù)量動(dòng)態(tài)調(diào)整編碼塊數(shù)量。各子編碼塊可以并發(fā)編碼解碼,加快編碼&解碼速度,提升整體傳輸性能;
- SDK側(cè)由 Doc -> Map -> JavaObject 的轉(zhuǎn)化方式調(diào)整為 Doc -> JavaObject,減少解碼端算力開(kāi)銷(xiāo)。
圖5 DGraph 傳輸編碼解碼過(guò)程優(yōu)化
四、用戶(hù)體驗(yàn)優(yōu)化
DAG圖調(diào)試功能優(yōu)化
目前我們已經(jīng)把DGraph DAG圖查詢(xún)的調(diào)試能力集成到DIP平臺(tái)。其原理是:DGraph 的算子基類(lèi)實(shí)現(xiàn)了執(zhí)行結(jié)果輸出,由于算子的中間結(jié)果數(shù)據(jù)量極大,當(dāng)調(diào)試模塊發(fā)現(xiàn)調(diào)試標(biāo)志后會(huì)先把當(dāng)前算子的中間結(jié)果寫(xiě)入日志中,數(shù)據(jù)按TraceID + DAGID+ NodeID 組織,最終這些數(shù)據(jù)被采集到SLS日志平臺(tái)。
圖6 DGraph DAG圖查詢(xún)調(diào)試
從DIP平臺(tái)調(diào)試DAG圖請(qǐng)求,首先通過(guò)DGraph JavaSDK的調(diào)試入口拿到DAG圖請(qǐng)求json,填入DIP平臺(tái)圖請(qǐng)求調(diào)試入口,發(fā)起請(qǐng)求。索引平臺(tái)會(huì)根據(jù)請(qǐng)求體自動(dòng)關(guān)聯(lián)DAG圖并結(jié)合最終執(zhí)行結(jié)果通過(guò)頁(yè)面的方式展示。DIP平臺(tái)拿到結(jié)果后,在DAG圖中成功的算子節(jié)點(diǎn)標(biāo)記為綠色,失敗的節(jié)點(diǎn)標(biāo)記為紅色(圖6)。點(diǎn)擊任意節(jié)點(diǎn)可以跳轉(zhuǎn)到日志平臺(tái)查看該節(jié)點(diǎn)的中間結(jié)果輸出??捎糜诜治鯠AG圖執(zhí)行過(guò)程中的各種細(xì)節(jié),提升業(yè)務(wù)排查業(yè)務(wù)問(wèn)題效率。
DAG圖支持TimeLine分析
基于Chrome瀏覽器中的TimeLine構(gòu)建,用于DGraph DAG圖查詢(xún)時(shí)算子性能分析優(yōu)化工作。TimeLine功能集成在算子基類(lèi)中,啟動(dòng)時(shí)會(huì)記錄每個(gè)算子的啟動(dòng)時(shí)間、等待時(shí)間、完成時(shí)間、執(zhí)行線程pid等信息,這些信息首先輸出到日志,然后被SLS日志平臺(tái)采集。用戶(hù)可以使用查詢(xún)時(shí)的TraceID在日志平臺(tái)搜索相關(guān)的TimeLine信息。
圖7 DGraph DAG圖例子
圖8 使用瀏覽器查看DGraph DAG圖 TimeLine
當(dāng)我們拿到請(qǐng)求的TimeLine信息后,通過(guò)瀏覽器加載可以通過(guò)圖形化的方式分析DAG執(zhí)行過(guò)程中耗時(shí)分布。圖7是一個(gè)DAG 請(qǐng)求,它有9個(gè)算子節(jié)點(diǎn),圖8是它的一次請(qǐng)求的TimeLine。通過(guò)分析這些算子的耗時(shí),可以幫助我們定位當(dāng)前DAG圖查詢(xún)的瓶頸點(diǎn)在哪里,從而精準(zhǔn)去解決性能方面的問(wèn)題。
DAG圖支持動(dòng)態(tài)子圖
在DAG圖召回中,業(yè)務(wù)的召回通常都帶有一些固定模式,比如一個(gè)業(yè)務(wù)在一個(gè)DAG圖召回中有N路召回,每一路召回都是:① 查找數(shù)據(jù);② 關(guān)聯(lián)可推池;③ 打散; 它們之間的區(qū)別可能僅僅是召回?cái)?shù)據(jù)表名不同或者傳遞的參數(shù)不同。通常我們業(yè)務(wù)調(diào)整或者算法實(shí)驗(yàn)調(diào)整只需要增加或者減少部分召回,原有模式下這些操作需要去新增或者修改DAG圖,加上算法實(shí)驗(yàn)很多,業(yè)務(wù)維護(hù)DAG圖的成本會(huì)非常高。
DAG動(dòng)態(tài)子圖的引入就是為了解決這類(lèi)問(wèn)題,首先我們?cè)贒AG圖中配置一個(gè)模板子圖,它僅僅描述一個(gè)行為模式,代表會(huì)涉及幾個(gè)算子,算子之間的關(guān)系如何,實(shí)際的參數(shù)以及召回路的數(shù)量則由業(yè)務(wù)方在發(fā)起請(qǐng)求時(shí)動(dòng)態(tài)決定。子圖的執(zhí)行和主圖的執(zhí)行共用同一套調(diào)度框架,共享運(yùn)行時(shí)資源以降低運(yùn)行開(kāi)銷(xiāo)。
圖9 DGraph 子圖
圖9是一個(gè)DAG召回使用DAG子圖后的變化,它有8路召回,一個(gè)Merge節(jié)點(diǎn),這些召回分為兩類(lèi),一類(lèi)是基于KV表(ForwardSearch)觸發(fā)的向量召回,另外一類(lèi)是基于KVV表(IvtSearch)觸發(fā)的向量召回。引入DAG子圖后,在主圖中節(jié)點(diǎn)數(shù)量由17個(gè)降為3個(gè)。
五、展望未來(lái)
過(guò)去四年,DGraph聚焦于實(shí)現(xiàn)得物推薦引擎體系從0到1的突破,重點(diǎn)完成了核心系統(tǒng)架構(gòu)搭建、算法策略支持及業(yè)務(wù)迭代空間拓展,取得多項(xiàng)基礎(chǔ)性成果?;?024年底的用戶(hù)調(diào)研反饋結(jié)合DGraph當(dāng)前的發(fā)展,后續(xù)將重點(diǎn)提升產(chǎn)品易用性、開(kāi)發(fā)與運(yùn)維效能及用戶(hù)體驗(yàn),同時(shí)在系統(tǒng)穩(wěn)定性、可擴(kuò)展架構(gòu)和平臺(tái)化建設(shè)方面持續(xù)深化。