解密游戲推薦系統(tǒng)的建設(shè)之路
一、游戲推薦的背景與意義
從信息獲取的角度來看,搜索和推薦是用戶獲取信息的兩種主要手段,也是有效幫助產(chǎn)品變現(xiàn)的兩種方式,搜索是一個(gè)非常主動(dòng)的行為,并且用戶的需求十分明確,在搜索引擎提供的結(jié)果里,用戶也能通過瀏覽和點(diǎn)擊來明確的判斷是否滿足了用戶需求。
然而,推薦系統(tǒng)接受信息是被動(dòng)的,需求也都是模糊而不明確的。推薦系統(tǒng)的作用就是建立更加有效率的連接,更有效率地連接用戶與內(nèi)容和服務(wù),節(jié)約大量的時(shí)間和成本。以此背景,游戲推薦系統(tǒng)由此誕生。
游戲推薦系統(tǒng)從設(shè)計(jì)之初就作為游戲分發(fā)的平臺(tái),向公司內(nèi)所有主要流量入口(游戲中心、應(yīng)用商店、瀏覽器、jovi等)分發(fā)游戲,系統(tǒng)通過各種推薦算法及推薦策略,為用戶推薦下載付費(fèi)意愿較高且兼顧商業(yè)價(jià)值的游戲,從而為公司帶來收入。發(fā)展至今天,該系統(tǒng)還具備類游戲內(nèi)容與素材的推薦功能。
二、游戲推薦的初期模型
游戲推薦的目的是推出用戶想要且兼顧商業(yè)價(jià)值的游戲,以此來提高業(yè)務(wù)的收入指標(biāo)。此處的商業(yè)價(jià)值是由運(yùn)營側(cè)通過策略規(guī)則去把控的,而用戶意向游戲則是通過算法排序得到的,算法排序所需要的特征數(shù)據(jù),以及推薦效果的反饋數(shù)據(jù)則由埋點(diǎn)信息上報(bào)以供計(jì)算分析。
因此我們的模型可以分成四大塊:
- 運(yùn)營推薦規(guī)則配置
- 算法模型訓(xùn)練
- 推薦策略生效
- 數(shù)據(jù)埋點(diǎn)上報(bào)
模塊間的交互如下:在策略生效前,運(yùn)營會(huì)先在配置中心生成對(duì)應(yīng)的配置規(guī)則,這些規(guī)則會(huì)以緩存的形式存儲(chǔ)以供推薦高并接口調(diào)用。當(dāng)用戶訪問app應(yīng)用某些特定頁面時(shí),其后臺(tái)會(huì)帶著對(duì)應(yīng)的場景信息來請(qǐng)求游戲推薦后臺(tái),推薦后臺(tái)根據(jù)場景信息映射相關(guān)配置(召回,標(biāo)簽,過期,算法等..........)調(diào)用算法服務(wù)并進(jìn)行資源排序,最終將推薦的結(jié)果反饋給app應(yīng)用。
app應(yīng)用在展示推薦頁面的同時(shí),也將用戶相應(yīng)的行為數(shù)據(jù)以及推薦數(shù)據(jù)的相關(guān)埋點(diǎn)進(jìn)行上報(bào)。
三、業(yè)務(wù)增長與架構(gòu)演進(jìn)
隨著接入系統(tǒng)帶來的正向收益的提升,越來越多的業(yè)務(wù)選擇接入游戲推薦系統(tǒng),這使得我們支持的功能日益豐富。
目前游戲推薦覆蓋的場景有分類、專題、榜單、首頁、搜索等;包含的策略類型有干預(yù)、打散、資源配比、保量;支持的推薦類型更是豐富:聯(lián)運(yùn)游戲、小游戲、內(nèi)容素材、推薦理由。
這些豐富的使用場景使得業(yè)務(wù)的復(fù)雜度成本增長,令我們?cè)谛阅?,擴(kuò)展性,可用性上面臨著新的挑戰(zhàn),也推動(dòng)著我們架構(gòu)變革。
3.1 熵增環(huán)境下的通用組合策略
在0 到 1 的過程中,游戲推薦聚焦于提高分發(fā)量,這時(shí)候考慮得更多的是怎么把游戲推出去,在代碼實(shí)現(xiàn)上使用分層架構(gòu)來劃分執(zhí)行的業(yè)務(wù)。
但是在1 到 2 的過程中, 我們游戲推薦不僅僅推薦游戲,也推薦內(nèi)容和素材;同時(shí)在策略調(diào)用上也更加靈活,不同場景其調(diào)用的策略是不同的,執(zhí)行順序也是不同的;更重要的是加入了很多用戶個(gè)性化業(yè)務(wù)與動(dòng)態(tài)規(guī)則,這些都使得現(xiàn)有業(yè)務(wù)代碼急劇膨脹,擴(kuò)展起來捉襟見肘,無從下手。因此我們急需一個(gè)高復(fù)用,易擴(kuò)展,低代碼的策略框架去解決這些問題。
如圖所示,通用組合策略負(fù)責(zé)流轉(zhuǎn)的角色有兩個(gè)acceptor和executor,通訊媒介是推薦上下文context。負(fù)責(zé)執(zhí)行邏輯的角色有三個(gè)matcher,listener和process,它們都有多個(gè)不同邏輯的實(shí)現(xiàn)類。當(dāng)請(qǐng)求游戲推薦系統(tǒng)時(shí),acceptor會(huì)先從配置中動(dòng)態(tài)查詢策略模板進(jìn)行匹配,接著listener組件會(huì)執(zhí)行相應(yīng)的預(yù)處理邏輯。處理后acceptor通過上下文context將任務(wù)流轉(zhuǎn)給executor處理器。executor再根據(jù)配置,將process根據(jù)前置條件進(jìn)行篩選并排列組合,最后埋點(diǎn)返回。
經(jīng)過這套通用的策略,我們?cè)趯?shí)現(xiàn)一般業(yè)務(wù)的時(shí)候,只要擴(kuò)展具體matcher和process,并在配置中心將場景和處理優(yōu)先級(jí)綁定起來,就能完成大部分的場景開發(fā),這樣研發(fā)者可以更聚焦于某個(gè)邏輯流程的開發(fā),而不用疲于梳理代碼,并進(jìn)行擴(kuò)展設(shè)計(jì)。
3.2 多級(jí)緩存與近實(shí)時(shí)策略
游戲推薦系統(tǒng)服務(wù)于手機(jī)游戲用戶,處于整個(gè)系統(tǒng)鏈路的下游,峰值流量在3W TPS左右 ,是個(gè)讀遠(yuǎn)多于寫的系統(tǒng)。“讀”流量來自于用戶在各種推薦場景,列表、搜索、下載錢下載后、榜單等,寫數(shù)據(jù)主要來源于運(yùn)營相關(guān)策略的變更,所以我們面臨的一個(gè)重大挑戰(zhàn)就是如何在保證可用性的前提下應(yīng)對(duì)高頻的讀請(qǐng)求。
為了保證系統(tǒng)的讀性能,我們采用了redis + 本地緩存的設(shè)計(jì)。配置更新后先寫mysql,寫成功后再寫redis。本地緩存定時(shí)失效,使用懶加載的方式從redis中讀取相關(guān)數(shù)據(jù)。這種設(shè)計(jì)能保證最終一致性,軟狀態(tài)時(shí)服務(wù)集群數(shù)據(jù)存在短暫不一致的情況,早期對(duì)業(yè)務(wù)影響不大,可以認(rèn)為是一個(gè)逐步放量的過程。
早期原先部署節(jié)點(diǎn)較少,整個(gè)系統(tǒng)達(dá)到最終一致性的時(shí)間較短,但隨著節(jié)點(diǎn)增加到數(shù)百臺(tái),這個(gè)時(shí)間就變得不是那么和諧了。
同時(shí)隨著業(yè)務(wù)復(fù)雜度的增加,常常是多個(gè)配置策略決定這一個(gè)推薦結(jié)果,此時(shí)本地緩存的狀態(tài)極大影響了測試和點(diǎn)檢的便利,如果配置更改不能做到立馬更新本地緩存,那就要等待漫長的一段時(shí)間才能開始驗(yàn)證邏輯。因此,我們對(duì)緩存結(jié)構(gòu)做出了如下的調(diào)整:
與先前不同的是,我們加入消息隊(duì)列并通過配置版本號(hào)的比對(duì)來實(shí)現(xiàn)策略的實(shí)時(shí)更新同步,取得了很好的效果。
3.3 高并服務(wù)的垃圾回收處理
任何一個(gè)java服務(wù)都逃離不了FGC的魔咒,高并服務(wù)更是如此。很多服務(wù)每天兩位數(shù)的FGC更是家常便飯,顯然這對(duì)業(yè)務(wù)的穩(wěn)定性和服務(wù)性能影響是巨大的。游戲推薦這邊通過不斷實(shí)踐總結(jié)了一套較為通用的方法很好地解決了這個(gè)問題:
可以看到起初jvm配置較為常規(guī):1G的年輕代,2G的老年代以及一些其他常見的多線程回收的配置,其結(jié)果就是每天10次的FGC,YGC單次耗時(shí)在100ms,F(xiàn)GC耗時(shí)在350 - 400ms。我們知道線上接口容忍的范圍一般是200ms以內(nèi),不超過300ms,這樣顯然是不達(dá)標(biāo)的。
通過分析,我們發(fā)現(xiàn)高并服務(wù)的高頻FGC來源于這幾個(gè)方面:
- 大量的本地緩存(堆內(nèi))占據(jù)了老年代的空間,大大增加了老年代疊滿的頻率。
- 高并請(qǐng)求導(dǎo)致了對(duì)象的急速生成,年輕代空間不足以容納這劇增的對(duì)象,導(dǎo)致其未達(dá)到存活閾值(15次)就晉升至老年代。
- 引入的監(jiān)控組件為了性能,常常延遲 1 - 2 min再將數(shù)據(jù)上報(bào)服務(wù)端,導(dǎo)致這部分?jǐn)?shù)據(jù)也無法在年輕代被回收。
當(dāng)然這還不是問題的全部,F(xiàn)GC還有個(gè)致命問題就是stop the world,這會(huì)導(dǎo)致業(yè)務(wù)長時(shí)間無法響應(yīng),造成經(jīng)濟(jì)損失。反過來,就算FGC頻繁,stop the world 只有1ms,也是不會(huì)對(duì)業(yè)務(wù)造成影響的,因此不能單單以FGC的頻率來判斷jvm服務(wù)的gc性能的好壞。經(jīng)過上面的探討,我們?cè)趯?shí)踐中得到了如下的解決方案:
- 不常變化的緩存(小時(shí)級(jí)別)移到堆外,以此減少老年代疊滿的基礎(chǔ)閾值。
- 變化不那么頻繁的緩存(分鐘級(jí)別)更新的時(shí)候進(jìn)行值對(duì)比,如果值一樣則不更新,以此減少老年代的堆積。
- 使用G1回收器:-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=25
-XX:MaxNewSize=3072M -Xms4608M -Xmx4608M -XX:MetaspaceSize=512M
-XX:MaxMetaspaceSize=512M
其效果如上所示,調(diào)整后各項(xiàng)指標(biāo)都有很大的進(jìn)步:由于年輕代中的復(fù)制算法使其垃圾清理速度較快,所以調(diào)大其容量使對(duì)象盡量在其中回收,同時(shí)設(shè)置每次清理的時(shí)間,使得mix gc控制在200ms以內(nèi)。
3.4 限流降級(jí)與兜底策略
為了保證業(yè)務(wù)的可用性,大部分業(yè)務(wù)都會(huì)引入hystrix, sentinel, resilience4j 這類熔斷限流組件, 但這些組件也不能解決全部的問題。
對(duì)于游戲推薦來說,一臺(tái)節(jié)點(diǎn)往往承載著不同的業(yè)務(wù)推薦,有些業(yè)務(wù)十分核心,有些不是那么重要,限流降級(jí)的時(shí)候不是簡單的哪個(gè)服務(wù)限流多少問題,而是在權(quán)衡利弊的情況下,將有限的資源向哪些業(yè)務(wù)傾斜的問題,對(duì)此我們?cè)诜謱酉蘖魃舷伦懔斯Ψ颉?/p>
同時(shí)對(duì)于個(gè)性化業(yè)務(wù)來說,僅僅返回通用的兜底會(huì)使推薦同質(zhì)化,因此我們的策略是將用戶的歷史數(shù)據(jù)存儲(chǔ)下來,并在下次兜底的時(shí)候作為推薦列表進(jìn)行返回。
四、精細(xì)化運(yùn)營模式的探索
在經(jīng)歷過了0 到1 的開疆拓土 與 1 到 2 的高速增長后,游戲的推薦架構(gòu)已經(jīng)趨于穩(wěn)定。這時(shí)候我們更加關(guān)注效能的提高與成本的下降,因此我們開始著手于系統(tǒng)運(yùn)營的精細(xì)化設(shè)計(jì),這對(duì)推薦系統(tǒng)的良性發(fā)展是意義重大的。
精細(xì)化運(yùn)營不僅能提高尾量游戲的收入,提高運(yùn)營人員的工作效率,還能實(shí)時(shí)快速反饋算法在線效果并立馬做出調(diào)整,做到一個(gè)業(yè)務(wù)上的閉環(huán)。首先就不得不提到游戲推薦系統(tǒng)的分層正交實(shí)驗(yàn)平臺(tái),這是我們做精細(xì)化運(yùn)營的基礎(chǔ)。
4.1 多層 hash 正交實(shí)驗(yàn)平臺(tái)
游戲推薦的關(guān)鍵就一個(gè)"準(zhǔn)"字,這就需要通過精細(xì)化策略迭代來提升效率和準(zhǔn)確度,從而不斷擴(kuò)大規(guī)模優(yōu)勢,實(shí)現(xiàn)正向循環(huán)。然而策略的改變并不是通過“頭腦風(fēng)暴”空想的,而是一種建立在數(shù)據(jù)反饋上的機(jī)制,以帶來預(yù)期內(nèi)的正向變化。這就需要我們分隔對(duì)照組來做A/Btest。
般線上業(yè)務(wù)常見的A/B test是通過物理方式對(duì)流量進(jìn)行隔離,這種方法常見于H5頁面的分流實(shí)驗(yàn),但面對(duì)復(fù)雜業(yè)務(wù)時(shí)卻存在著部署較慢,埋點(diǎn)解析困難等問題,其典型的架構(gòu)方式如下:
對(duì)于游戲推薦來說,其完成一次推薦請(qǐng)求的流程比較復(fù)雜,涉及到多組策略,為了保證線上流量的效率與互斥,就不能采用簡單的物理分配流量的方式。
因此在業(yè)務(wù)層我們建立了一套多層hash正交實(shí)驗(yàn)規(guī)則來滿足我們A/B test的要求。
與物理隔離流量,部署多套環(huán)境的方式不同,分層模型在分流算法中引入層級(jí)編號(hào)因子(A)來解決流量饑餓和流量正交問題。每一實(shí)驗(yàn)層可以劃分為多個(gè)實(shí)驗(yàn)田,當(dāng)流量經(jīng)過每一層實(shí)驗(yàn)時(shí),會(huì)先經(jīng)過Function(Hash(A)) 來計(jì)算其分配的實(shí)驗(yàn)田,這樣就能保證層與層之間的流量隨機(jī)且相互獨(dú)立。其流量走勢如下圖所示,
以上就是推薦業(yè)務(wù)和一般業(yè)務(wù)實(shí)驗(yàn)流量隔離的不同之處,在實(shí)驗(yàn)設(shè)計(jì)上我們又將一個(gè)完整的實(shí)驗(yàn)周期分為以下幾個(gè)階段。在預(yù)備階段需要跟根據(jù)業(yè)務(wù)指標(biāo)的需求,提出實(shí)驗(yàn)假設(shè),劃分好基線和實(shí)驗(yàn)田的流量比例,并上線配置(放量)。
在實(shí)驗(yàn)階段,線上流量進(jìn)入后,服務(wù)會(huì)根據(jù)流量號(hào)段的匹配響應(yīng)的策略進(jìn)行執(zhí)行,并將實(shí)驗(yàn)數(shù)據(jù)上報(bào)。放量一段時(shí)候后,我們會(huì)根據(jù)上報(bào)的埋點(diǎn)數(shù)據(jù)進(jìn)行數(shù)據(jù)分析,以確定此次策略的好壞。
和實(shí)驗(yàn)階段劃分相對(duì)應(yīng)地,我們將實(shí)驗(yàn)平臺(tái)劃分為實(shí)驗(yàn)配置,埋點(diǎn)上報(bào)和實(shí)驗(yàn)結(jié)果分析三個(gè)模塊,在實(shí)驗(yàn)配置模塊,我們根據(jù)實(shí)驗(yàn)需求來完成分流配置和業(yè)務(wù)場景的映射關(guān)系。
并在hash實(shí)驗(yàn)管理中將業(yè)務(wù)層級(jí)劃分,以便流量的流通。
在埋點(diǎn)上報(bào)模塊中,我們通過sdk的方式植入業(yè)務(wù)代碼中,當(dāng)流量進(jìn)入該實(shí)驗(yàn)田時(shí)就會(huì)進(jìn)行分析和埋點(diǎn)上報(bào),我們將上報(bào)的埋點(diǎn)分為游戲和請(qǐng)求維度,節(jié)省上報(bào)流量的同時(shí)以滿足不同的分析需求:
在實(shí)驗(yàn)結(jié)果分析模塊中,我們將采集的埋點(diǎn)的數(shù)據(jù)上報(bào)只大數(shù)據(jù)側(cè),并由其進(jìn)行分析計(jì)算,其結(jié)果指導(dǎo)這我們對(duì)實(shí)驗(yàn)策略進(jìn)行進(jìn)一步的分析迭代。對(duì)于游戲請(qǐng)求的上報(bào)格式,我們可以直接通過appId和gameps的信息直接分析得出該類游戲的推薦結(jié)果和用戶行為的關(guān)系。同時(shí)加入請(qǐng)求維度的分析(包含策略信息),可以直接分析出決策對(duì)各項(xiàng)指標(biāo)的影響。
4.2 召回優(yōu)化之多路召回
召回在游戲推薦業(yè)務(wù)中就是利用一定的規(guī)則去圈選一批游戲,這是為了將海量的候選集快速縮小為幾百到幾千的規(guī)模。而召回之后的排序則是對(duì)縮小后的候選集進(jìn)行精準(zhǔn)排序,最終達(dá)到精準(zhǔn)推薦的目的。
然而這種單路的召回在業(yè)務(wù)上卻有著很大的缺陷:
- 通常為了保證計(jì)算效率,圈選的數(shù)量在幾百個(gè)左右,由于數(shù)量限制其無法完全覆蓋完整的目標(biāo)用戶候選集。
- 隨著業(yè)務(wù)的復(fù)雜度變高,召回策略的種類也開始膨脹,其召回規(guī)則是剝離的無法統(tǒng)一,這也意味著在某些業(yè)務(wù)場景下,在種類上無法覆蓋完全。
因此,權(quán)衡了計(jì)算效率和業(yè)務(wù)覆蓋度(召回率)的問題,我們逐步上線了多路召回功能。
在業(yè)務(wù)實(shí)現(xiàn)上,多路召回兼容了原有的個(gè)性化召回、算法召回、游戲池召回、分類/標(biāo)簽/專題/同開發(fā)者)召回等召回路徑,通過圈選多個(gè)游戲池做為召回策略,經(jīng)過合并、過濾、補(bǔ)量、截?cái)嗟炔呗宰罱K篩選出一批進(jìn)行算法預(yù)估打分的游戲。
本質(zhì)上,多路召回利用各簡單策略保證候選集的快速召回,從不同角度設(shè)計(jì)的策略保證召回率接近理想狀態(tài)。
4.3 曝光干預(yù)之動(dòng)態(tài)調(diào)參
一個(gè)推薦系統(tǒng)的效能如何,除了運(yùn)營策略之外很大程度上取決于推薦算法的結(jié)果,而推薦算法的結(jié)果又是以曝光量,下載量,ctr等作為評(píng)價(jià)指標(biāo)的。所以在游戲推薦業(yè)務(wù)的生命周期中,推薦算法一直致力于優(yōu)化這些指標(biāo)。
但是在開發(fā)中有個(gè)實(shí)際問題就是,從算法結(jié)果的數(shù)據(jù)反饋,到代碼改進(jìn)上線這個(gè)時(shí)間周期較長,對(duì)一些需要快速響應(yīng)的業(yè)務(wù)場景來說是不符合要求的。因此我們需要一套規(guī)則來對(duì)線上的算法結(jié)果做動(dòng)態(tài)調(diào)整,以滿足業(yè)務(wù)的要求,這就是動(dòng)態(tài)調(diào)參。
目前游戲業(yè)務(wù)的營收中,曝光量是個(gè)極其重要的指標(biāo),而大盤在一段時(shí)間內(nèi)的曝光量是確定的,太多或太少都會(huì)嚴(yán)重影響業(yè)務(wù),由此推薦算法就會(huì)根據(jù)線上實(shí)時(shí)反饋的一些數(shù)據(jù)對(duì)游戲的曝光進(jìn)行調(diào)整。
經(jīng)過設(shè)計(jì), 我們先將調(diào)參游戲劃分為多個(gè)等級(jí),并將游戲的生命周期劃分為幾個(gè)時(shí)間段,同時(shí)在每個(gè)時(shí)間段內(nèi)以游戲曝光量,評(píng)級(jí),數(shù)量等因素作為計(jì)算因子來計(jì)算曝光的分配權(quán)重。
接著系統(tǒng)根據(jù)實(shí)時(shí)采集的游戲曝光信息及所計(jì)算的游戲目標(biāo)曝光對(duì)實(shí)際曝光進(jìn)行調(diào)整,最終實(shí)現(xiàn)游戲曝光的動(dòng)態(tài)調(diào)控。
對(duì)于正向調(diào)控來說,動(dòng)態(tài)調(diào)參就是最有效的扶持機(jī)制,增加了游戲曝光的同時(shí)提升了導(dǎo)流能力。對(duì)于負(fù)向調(diào)控,動(dòng)態(tài)調(diào)參能對(duì)品質(zhì)和要求不達(dá)標(biāo)的游戲,通過減少曝光的方式進(jìn)行打壓,提升用戶體驗(yàn)。
五、展望之智能化建設(shè)
經(jīng)過多年的探索實(shí)踐,游戲推薦系統(tǒng)成就了一套完整的推薦體系。
在架構(gòu)上的演進(jìn)使得我們能更好地應(yīng)對(duì)復(fù)雜多變的業(yè)務(wù)需求,在精細(xì)化運(yùn)營上的探索與建設(shè)令我們能更加敏銳地把握住市場的變化以做出響應(yīng),這些建設(shè)也很好地反饋的反饋到了業(yè)務(wù)結(jié)果中,提升了眾多效能和收益指標(biāo),得到了業(yè)務(wù)方的一致好評(píng)。
但當(dāng)分發(fā)效率和收入效益問題解決了之后,我們?cè)谒伎甲约哼€能做什么,原先游戲推薦做的比較多的是接入服務(wù),在單鏈路上去做閉環(huán)提高效益,但這是遠(yuǎn)遠(yuǎn)不夠的。
在未來我們會(huì)考慮如何打造覆蓋搜廣推+ 智能運(yùn)營的全棧業(yè)務(wù)支撐系統(tǒng)(智能禮券,智能push,用戶反饋智能處理系統(tǒng)),以提升平臺(tái)和渠道的價(jià)值。