快手關於海量模型資料處理的實踐

一、模型場景介紹

1.即時大模型

圖片

*本文資料具有即時性,不代表即時資料。

快手的模型場景主要是即時的大模型。實時主要體現在社交上。每天都有新用戶上傳1500 萬以上的視頻,每天有億級以上的直播活躍用戶,並且上傳數每年都在同比上漲。

大主要體現在流量規模。快手現在的日活達到了3.87 億,有千億級別的日均曝光,百億級別的日均播放,模型量級非常大,還要保證實時。而快手的核心價值是平等普惠,也就是千萬級的用戶同時在線上時,個人化請求時會推薦不同的內容。

總結起來,資料處理的特點是既大,又要即時。

2、推薦業務複雜

圖片

一般的推薦業務架構如上圖所示,在視訊池裡(例如有數千萬的影片)會經過固定的四個階段:

  • 召回:從幾千萬的影片召回幾萬或幾千的影片。
  • 粗排:透過一個粗排漏斗,選出幾千的影片。
  • 精排:幾千的影片又會通過精排,篩選top 幾百的影片。
  • 重排:進入重排,給模型評分,做模型校驗。
  • 回傳:加上一些機制和多樣化操作,最後選出幾十個結果回傳給用戶,整個漏斗要求非常高。

快手的業務類型比較多樣,主要可以分成大型業務和中小型業務。

大型業務的樣本量級很大,像主站建議一天的樣本可能有千億,儲存能達到p 的等級。迭代主要用流式迭代,即在線迭代特徵和模型,速度會非常快。如果選用批次迭代的話,回溯樣本要30 天,需要的資源是流式迭代的幾十倍,快手大場景下的流量分配又比較多,所以傾向於做在線的流式迭代實驗,速度快,消耗資源量相對也少很多。

中小業務,一天的樣本大約在百億級別,存放大概幾十T。選擇串流迭代會需要頻繁上線迭代,而且流量分配也不夠。這種情況下一般盡量選用批式迭代,此時需要大量層級的計算樣本,例如要回溯至少60 天以上,回溯樣本能達到p 等級。因為對於大模型來說,如果資料量不夠,模型訓練不充分,效果就會隨之下降。所以在這種小的業務場景裡,還是傾向批式迭代,回溯更多天的樣本,讓模型達到更穩定的狀態。在這種場景下面,會傾向批次迭代實驗。

3.推薦模型的資料量

圖片

這裡是之前在快手發布的一個萬億級別模型文章裡的截圖,快手是個人化模型,所以參數量非常大。從圖中比較來看,OpenAI 的GPT3 參數量是175B,但快手參數量1900B,已經到兆等級了。主要是因為快手選用的是SIM 長序列模型,需要使用者長期的興趣,然後把該序列輸入到模型中。快手有億級用戶,life-long 興趣需10 萬以上序列,再加上千億級的樣本的疊加,因此參數量非常大,能達到1.9 兆。雖然這1.9 兆參數跟OpenAI 的GPT 3 模型的參數型別不一樣,計算量也不太一樣。但從參數量級來看,快手推薦是非常大的。

4.語言模型的演進

圖片

推薦模型跟語言模型緊密相關,一般新模型都會在語言模型上去做迭代,成功之後就會引入推薦模型,例如DN、RNN、Transformer。上圖是亞馬遜3 月時發布的圖,主要介紹了語言模型的一些進展。

可以看到,17 年之前主要是RNN 模型,RNN 模型是按次序去順序遍歷資料後訓練,該模型對平行算力要求並不高,但模型收斂比較複雜,因為可能會出現梯度消失的問題。 2017 年出現Transformer 之後,語言模型突破了原有的限制,可以做並發迭代,所以其算力大規模成長。

圖中的樹分為三個部分:(1)紅線部分是encoder-only 技術,最早是Bert 模型;(2)綠線是encoder-decoder 類型,Google 主要選擇這一類型;(3)藍線主要是open API 裡ChatGPT 選用的類型,這一類模型發展得最好,因為它夠簡單,只需要考慮decoder,運算量小,而且模型效果也會很好。

二、大規模模型資料處理

1、背景-實效性

圖片

快手對資料時效性要求很高,使用者看到影片後會回饋到快手的log 收集系統,該使用者的行為會即時地拼接推薦日誌(推薦日誌就是推薦服務落下來的特徵),特徵流加上行為流成為樣本流進入後面的特徵處理,然後進入模型訓練。模型訓練完成後即時更新到線上預估,線上預估會根據模型的更新推薦出最符合用戶需求的一些影片。此連結要求延遲必須要在一秒鐘內,需要盡快將使用者行為回饋到模型裡,所以對於大數據處理的時效性要求是非常高的。

2、大數據量處理

圖片

快手有千萬級用戶在線,不考慮行為多樣性的情況下,QPS 至少是千萬​​級的,如果區分到行為的多樣性,這個組合數量就更爆炸了,高峰期大概每秒需要處理30T 左右的狀態。

業界方案主要是採用Flink 串流框架,但如果直接用Flink 引進state join,在並發幾千的情況下會造成大量的慢節點。因為30T 狀態如果1000 並發的話,需要存30G 的狀態,如果1 萬併發也得存3G。 3G 在1 萬並發下的慢節點的機率會非常大。在這種情況下如果出現慢節點,需要幾個小時來恢復,這對於推薦系統肯定是不能忍受的。

所以快手選擇了一個折中方案,把狀態下沉至高效能儲存上,然後採用無狀態hash join 的方式來做一個即時join 的狀態,只要用戶的行為和特徵都到齊,就立即觸發樣本的下發,這樣就可以保證行為能夠及時地回饋到模型。雖然特徵和行為來的順序不一樣,但透過外部的狀態,再加上Flink 串流框架並行的操作,就能實現大規模高效能的join。

3.複雜特徵計算

圖片

在上述處理完成之後,是特徵計算場景,主要有兩種計算,標量計算和向量計算。標量計算類似特徵處理,例如要把某些值求和、求平均。在向量計算裡,會對一批樣本同一列進行一個相同的操作,放在GPU 透過cuda 計算。這樣,透過使用GPU 和CPU 協同的方式實現高效能運算,一些標量操作在CPU 上運算,記憶體存取也會在CPU 上進行,然後傳輸到GPU 上去做高效能的GPU 運算。

為了確保演算法迭代的彈性,採用了DSL 抽象。因為SQL 不能完全描述所有的特徵處理場景。例如有一些在時間視窗的操作,如果透過SQL 去做需要寫一些自訂的UDF,這樣很不利於迭代。所以我們的DSL 是用Python 描述的,使用者可以透過Python 直接呼叫下層的高效執行算子。第一步先寫計算層,使用C++ 實作一些高效率的operator,包含cuda 和CPU 相關的運算也都是透過C++ 函式庫去做的。在runtime 下面採用Flink 的分散式框架加上GNI 的方式去呼叫C++ 的這些算子,以達到高效能、高吞吐的處理。

4.推薦場景特點

推薦場景下有兩個特點,一個是批流一體,另一個是潮汐。

圖片

批式研究和線上實驗這兩種場景會需要有批流一體,因為在批場景裡研究特徵或研究模型結構完成之後,需要到在線去做上線,因此需要有一個批流一體的統一描述語言加上統一的執行引擎。使用者在批式上調查,會使用DSL、Hadoop 和Spark 把所有的資料計算出來,做模型迭代。模型迭代成功之後做特徵上線,上線到流式通用特徵處理框架上,或是上線到流式特徵框架特化的一個處理框架上。這裡之所以會分出兩個節點,主要是因為有些特徵是所有模型公用的,所以可能在通用的框架下面,這樣只需要計算一次。而在特化的算子下面則是一些模型所特有的特徵,因此分開處理。但這兩個計算引擎和語言描述其實是一樣的。同樣地,這些通用處理的資料需要落盤到批次場景下。批場景下有很多是基於base 的特徵去迭代,會加入它自己的性價特徵,所以在批次場景下面計算的也是Delta。

上線完之後就會到線上服務,這裡會有一個高效能的儲存和運算庫去承接,這一點在後文中還會講到。在串流場景下,注重的是高吞吐、低延遲和高可用。在批場景下,主要關注高吞吐、高可靠。

圖片

另外一個特點就是請求潮汐。上圖是請求潮汐的示意圖(並不是快手的真實流量)。從圖中可以看到,有早高峰和晚高峰兩個高峰。在高峰期需要給足在線的算力,在低高峰期則要把冗餘的算力利用起來。

在這種情況下,快手的大數據處理框架以及線上所有的模組需要針對潮汐的特點,去做雲原生架構的一些改造,例如快速恢復、自動伸縮、快速伸縮。快速伸縮主要是因為在自動伸縮的時候並不能保證是高效的,例如一次自動伸縮需要耗一小時或幾個小時之久,那麼在線的請求在這幾個小時之間會有比較大的損失。

另外,還需要把線上服務的資源池和大數據處理的資源池統一起來,這樣所有資源在低高峰期時可以把冗餘算力給批式場景、大模型預訓練場景或大模型批量預估的場景,使資源得以利用。快手現在所有的架構都在向雲端原生架構演進。

三、大規模模型資料存儲

1、儲存特點

圖片

大規模資料儲存的第一個特點就是超低延遲,因為儲存節點儲存的都是狀態,有些運算節點需要很多的狀態資訊才能去計算,所以儲存節點大部分時間都是在葉子節點,而且建議的線上實驗有上千個模組,每一個模組只能給十毫秒以內或最多幾十毫秒的超時時間,因此要確保所有儲存節點都是低延遲、高吞吐並且高可用的。

推薦實驗和推薦服務base 之間有一個互相切換的流程。一般並行的實驗數量非常多,實驗完成之後會去切換成一個在線的base,這樣它所承擔的流量就會非常大。例如在訓練服務base 裡會有召回的base、粗排的base和精排的base,各個base 都需要去承擔千萬級的QPS,而且要提供超高的可靠性。所以在線上儲存部分,大量選用的是全記憶體架構。

圖片

其次,快手有超大儲存的需求。前文提到,快手大模型有1.9 兆的參數量,如果換成普通八維的float,需要的儲存也要有64T,而且還有一個全用戶的行為序列,有180T 左右的狀態資訊。如果要採用全內存的存儲,將會需要2000 多台機器。而且所有的狀態都需要在30 分鐘內恢復,因為推薦系統如果超過30 分鐘不恢復,會對線上產生非常大的影響,使用者體驗會很差。

針對上述需求,我們的方案主要有以下幾個:

  • 特徵score 的進入:特徵score 可以理解為特徵重要性,即將一些重要性比較低,對預估效果影響也微乎其微的特徵不放在在線存儲上。
  • LRU 和LFU 的淘汰:因為是在線的模型,需要保證可靠性,即內存需要維持在一個穩定範圍內,不能一直增長。因此我們將最遠更新的優先淘汰,最先訪問的優先保留。
  • NVM 新硬體技術:全記憶體架構的資源消耗也是一個非常大的問題。我們引進了NVM 硬體技術。 NVM 是一個持久化存儲,是Intel 新發布的一個硬件,它會在DR 和SSD 之間,有接近於內存的速度,同時有接近於SSD 的存儲空間,既能兼顧存儲也能兼顧性能。

2、儲存方案-NVM Table

圖片

儲存方案是NVM Table,分成異質儲存的三層:實體層提供底層儲存的API,包括NVM 儲存和memory 儲存;中間memory pool 封裝統一的管理功能,把NVM 和memory 的模組都管理起來;上層業務透過memory pool 的一個API 去呼叫下層的NVM 和memory,提供統一的查詢邏輯。

在資料結構佈局方面,memory pool 採用的是block 介面抽象。將NVM 和memory 分成若干不同的、可透過全域統一位址來存取的block,這樣就可以實現zero copy 的存取自由化。對於一些頻繁存取的key,會放到mem-key 上。不常訪問的key 會放在到NVM 上。一些索引的key 會頻繁訪問,但查找到key 之後,其value 在最後要返回給上游的時候才會用到,並且量級較大,所以將value 放到持久化的存儲。 Key 查詢比較多,同時也比較小,所以放在內存,這樣就實現了內存和NVM 的零拷貝技術。這裡的哈希表採用了業界領先的無鎖技術,以減少臨界區的競爭,完成高效儲存。

從NVM Table 的一個場景測試資料可以看出,其網路的極限吞吐與JIRA 是相當的。跨網路存取一般是網路達到極限,所以NVM 頻寬可以完全覆蓋網路頻寬,瓶頸主要在網路上,這樣就能保證NVM 既有成本上的效益,也有大儲存和高吞吐的效益。另一方面,恢復時間也下降了120 倍。最開始恢復T 的資料需要兩個小時,採用NVM 之後只需要2分鐘。

圖片

3.儲存方案-強一致性

圖片

儲存方面,還有強烈一致性的需求,主要是因為在推薦場景裡也有一些廣告和電商的推薦,需要儲存的副本特別多。因為當一些新的短視頻或新物料進來時,下游所有模組會有一個並發分發,需要保證這些視頻在10 秒內到達所有的推薦服務,且所有推薦服務裡的狀態需要保證一致。否則對於模型的效果影響很大。

我們採用了Raft 協議加BT 的模式。 Raft 協定主要負責選組和同步數據,BT 的模式主要是改造BT 同步的模式,例如在幾千上萬台機器規模下的同步,如果同時用主從同步的話,主節點的出口頻寬可能會是從節點的千倍以上,頻寬就會變成瓶頸,下發的狀態就會非常少,高吞吐和資料同步會受到影響。

我們的方案是分散式的平衡樹分發,建構一個平衡二元樹,把所有主從節點進行組織,每個節點只管有限個從節點,從而保證從主節點同步到葉子節點所需的頻寬不變,但是單節點的頻寬限制為小於等於2,這樣在全域下既能做到一次性,也能做到高效地同步,10 秒內即可將所有視訊狀態分發到每個節點。

四、展望

圖片

推薦模型的發展跟語言模型是相關的,從DNN 模型到Wide&Deep,到Transformer,再到SIM 長序列及生成式模型,模型成長了許多倍。除了模型的成長,算力成長也會隨影片的成長和使用者的成長,呈現指數級的上升。從統計數據來看,最近兩年推薦模型的算力成長接近10 倍,我們的方案主要是優化工程架構和新的硬體技術。

圖片

生成式模型會帶來計算量的爆炸,因為它是一個token-based 的推薦,每次推薦都需要之前所有的token 作為context,在這種情況下產生的效果才會最好。如果沒有token-based,那麼與算力不會呈指數級增長。因此,建議的壓力,將主要來自狀態存儲的大規模提升,因為目前的推薦模型主要是pointwise 的推薦,對於長序列推薦模型算力也是有限的。如果全部採用深層模型推薦,其狀態儲存將再成長10 倍,挑戰會非常大。因此我們需要透過一些新硬件,例如CXL、NVM 以及新推出的Grace 架構,再加上工程上的優化,例如狀態做差分、傳輸計算等等,來應對未來的挑戰。