QQ空間廣告業(yè)務系統(tǒng)海量服務實踐
4月17日QCon業(yè)務架構專場會議上,騰訊QQ空間營收功能后臺技術負責人馮啟航以“QQ空間平臺百億級流量的社交廣告系統(tǒng)海量實踐”為主題,用自身在QQ空間增值營收服務上的多年探索經驗,為大家分享了他對于大數據為增值營收帶來新的增長引擎的獨特思考。以下是馮啟航的分享實錄:
馮啟航:大家下午好,我是來自騰訊的馮啟航,2010年畢業(yè)一直就職于QQ空間,現(xiàn)在是QQ空間的營收以及人工智能后臺的負責人。今天要講的是我們一直建設了差不多四年左右的廣告系統(tǒng)。互聯(lián)網的商業(yè)模式就是流量變現(xiàn),這對產品很重要的過程,做營收的,怎么把流量合理應用起來,是我們一直要解決的問題,今天分享的就是怎么流量變現(xiàn)的服務實踐,以往講廣告系統(tǒng)挺多是講廣告的算法,今天是更多的講工程實踐。
***部分講業(yè)務背景,第二部分講我們在架構過程中的一些設計思路,列舉一些具體的案例看看實踐的問題,第三部分講一下做ROI提升做的事情,***再小結一下。
業(yè)務背景:空間里的廣告除開廣點通的效果類的展示廣告外大部分流量都是自己平臺管理的,比如有品牌類展示廣告,還有平臺自身的推直播、UGC功能,黃鉆收入的需求,我們這些視作內部的大廣告主,他們的問題是我們聚焦要解決的。
今天分享的系統(tǒng)叫QBOSS,取這個名字是最開始建設定位于Qzone業(yè)務支撐系統(tǒng),隨著發(fā)展,QQ空間等產品接入廣告渠道有數百個,系統(tǒng)每天的有三百億左右的日常流量,流量訪問是很大的,日常峰值40萬每秒,性能要求高,我們的要求是整個廣告請求耗時在50ms內。
架構設計的***步是理清一些業(yè)務概念。

中間核心是廣告,根據廣告的業(yè)務特點分了四個維度四個方向上設計了概念。首先在廣告的左側是建立渠道的概念,有利于規(guī)范的管理。右側是體現(xiàn)平臺和產品運營導向的一些內容,例如作為對平臺健康來說,防止廣告對用戶進行騷擾也很重要,比如用戶重復看過的廣告還出現(xiàn)這是不允許的,還有就是按時間排期,優(yōu)先級等體現(xiàn)平臺產品的運營導向的。上面的方向是真正用戶能夠感受到廣告體驗的,我們稱為資源,它分為兩部分,一個是素材數據,這個圖片是什么樣子,視頻是什么樣子,這是素材問題,另外還有一個很值得說的,對開發(fā)者我們給他一個控制展示邏輯json模板的DIY定義機制,他是能夠支持開發(fā)者結合渠道制定自己展示邏輯,這也是一個很關鍵的設計,它做到了讓渠道業(yè)務的邏輯和廣告系統(tǒng)解耦,而且對開發(fā)組非常友好。廣告概念下面的方向是講用戶細分,廣告給更合適的用戶,避免全量用戶去展示,騷擾用戶也浪費了流量。在這個方向也有很多算法和大數據的發(fā)展空間。
騰訊通用技術積累
看經典的三層架構里,接入層有TGW WNS MSF TSW等,。中間層里SPP是騰訊內部最多使用的后臺服務開發(fā)框架,把網絡通信相關的功能都已經收歸了。還有一個同步中心,這是我們Qzone自研的,因為Qzone這樣量級的產品肯定是存在異地服務的,現(xiàn)在是深圳、上海、天津三地同步服務的,就涉及到數據的同步問題,我們都抽象成一個公共服務建設出來做了同步中心。另外我們用的比較多的是SSVR,它類似于一種隊列型的服務,但是不一像大家經常看到的云隊列的服務,我們是一個流水來實現(xiàn)本地隊列的服務,這個簡單可控,實踐證明這么多年用下來沒出什么問題。存儲層的選型比較多,首先CKV是騰訊最廣泛使用的產品,CDB是在MySQL上建立起來的,Redis用的也是比較多,TDW是針對海量數據做的一個數據庫。
左邊是一些系統(tǒng)或者組件,比如織云是我們的運維門戶包含了很多運維標準工具和流程;L5是做負載均衡的,羅盤、DC上報、CRA等是報表系統(tǒng)依賴的系統(tǒng) ,神盾是推薦引擎,另外當然有成熟CDN支持我們的廣告素材數據發(fā)布和訪問。那我們搭一個海量系統(tǒng)還需要做什么事情?用它來湊一湊,這個就比較靠譜了?其實整個廣告系統(tǒng)麻雀雖小五臟俱全,很多非核心服務我在這里就不贅述了。今天重點講的在線服務有策略中心、用戶中心,數據中心,還有離線處理部分,主要把用戶的數據處理上去。我們的客戶系統(tǒng)終端覆蓋PCQzone,獨立版APP,QQ,接入渠道是個人中心,應用開屏,F(xiàn)eeds廣告。先看策略中心是很綜合的一個服務,相當于廣告系統(tǒng)的中控,把SSP \DSP\DMP都結合起來了。這里都是重控制邏輯的部分,分享里也不贅述。
用戶中心服務,先從DMP建設開始
像上圖左邊這樣,我們去搜集很多平臺相關的活躍特性,你是不是黃鉆,是不是登錄活躍用戶,把這些數據建立成一個標簽,廣告主就可以任何組合選出一個用戶群定義出來。還有一種是號碼包方式,騰訊內部還有很多做數據挖掘的團隊,另外騰訊的業(yè)務實在太大了,很多的數據產生方,不能都集合到我這里來,你必須用號碼包的方式組織起來,這個用的比較廣泛。最開始最簡單的架構就是對外服務,提供一個協(xié)議就是詢問用戶是不是這個用戶群的,服務就回答YES or NO,就是做了一個匹配邏輯,把用戶的數據和用戶群定義的數據做一次比對,這是最簡單最開始的架構,但是遇到了一些問題,一個是你DMP要做強大,你的tag數據一定要做的多,tag來源很多,很多的數據團隊并不一定他的數據會放在你這個地方。就算是給你離線緩存有這個權限,對你的系統(tǒng)來說也是很大的負擔,還有個成本就是開發(fā)效率,投放體驗優(yōu)化等,做這個系統(tǒng)的時候人力緊張,有的廣告系統(tǒng)的團隊專門做這個,而我們這里只有一到兩個人開發(fā)做這個DMP,必須關注研發(fā)的效率。再就是內存存儲成本,性能要求決定了你的存儲的選型只能用內存,但是內存設備價格太高了,如果DMP都存下所有數據那你想想這幾百個指標要多少數據容量和設備呢?
我們帶著問題繼續(xù)往下走。***個問題,我們怎么提高用戶畫像tag的建設效率,之前怎樣做的呢?其實很多兄弟團隊還是這樣做的,比如我要做年齡和性別進來,一定是在TLV協(xié)議上取一個新的名字,這樣每增加一個tag效率是很低的 ,每個標簽的增加需要開發(fā)介入,更改協(xié)議,更改匹配邏輯的代碼。后來我們決定,放棄這個設計,采用bit協(xié)議來管理(如下圖),增加一個tag就是增加一個ID是很簡單的事情,bit的資源就是上線一套存在就有64位上去,再增加一套就是128了,對資源有分配序號的,每一個tag要新增我就給你分配對應的bit,我新增一堆tag沒有工作量了只需要分配。
第二個問題是增加一個適配層來處理數據來源。其實騰訊還有很多是有數據的技術團隊,但是沒有渠道觸達用戶,我們把這個數據接入能力做成適配協(xié)議后,走出一個插件式高效率的方式開放出去。數據團隊按這個協(xié)議寫好服務,接入就可以提供給廣告主使用了。另外適配也可以兼容一些必須實時訪問的tag數據服務方。
第三個問題是號碼包定投,一開始我們想的也比較簡單,用nosql存儲存用戶uin為key,value是包含某個號碼包id的數組,存一下用戶在哪個號碼包里面,每次訪問的時候拿這個數據判斷就行了,看起來很簡單很容易理解,但是實踐的時候會發(fā)現(xiàn)有缺點.首先是投放體驗,投放一個五千萬或者一億的號碼,系統(tǒng)需要把這個號碼的所有用戶的數據都拿出來一邊讀一邊寫。那這樣一個投放操作需要影響在線的服務,因為他要改在線的數據,在線的容量也會受到影響,而且廣告主什么時候投放號碼包也不確定,投放幾個也不知道,對外網服務的穩(wěn)定性造成的風險挺大的。并且我們有三個地方的服務,深圳上海天津,如果你在深圳投放,你還要同步這個數據到上海和天津,耗時更長。存儲回收也比較麻煩,很多號碼跟著廣告走的,廣告一旦下線,這個數據的意義就不大了,但是你很難回收。你只能把這個號碼拿出來再更新一下。我們以前做過被動的更新,當你用到這個用戶的時候再拿出來比對是否過期,不過這是非常被動的。解決這個問題,我們用了Qzone自研的存儲利器好友參與系統(tǒng),非常適合改造出適合號碼包的topic類型存儲,我們認為topic是個主題,是否參與一個游戲、是否在一個號碼包里,都可以看作topic主題。以前最火的QQ農場,你可以看到有多少個好友在玩農場,上千個好友都要看他是否在玩農場,這是非常大的計算量,于是我們就做了這個存儲系統(tǒng)。我們可以根據這個存儲系統(tǒng)的數據結構需求,把順序的號碼包數據處理成一個Btree樹結構,還有他用tmpfs處理這個號碼包,使得每個btree文件就是服務器上可以管理的文件,可視化的,我們的深圳上海天津三地同步也很簡單,只需要跨地域同步文件就可以,現(xiàn)在都是可視化操作了。管理方便,回收數據也很方便,直接刪除文件即可。性能也非常好。
數據中心服務。它的難點主要是管理用戶的廣告反饋數,廣告系統(tǒng)里面,數據中心和其他的和UGC很大的功能不同是,他是讀多寫多的訪問模型,為什么這么說呢?比如最普通的場景里:一次廣告曝光,曝光之前我需要看一下這個用戶有沒有看過這個廣告,就需要再讀一次,如果覺得這個用戶能夠被曝光,他就要寫一下廣告記錄,所以每一次曝光都需要讀寫這個數據,讀和寫的頻次都是很高的。不同于普通的功能類型產品,我發(fā)表一個說說相冊一般來說都是讀的情況很多,寫的情況相對很少。另外我還是存在需要異地服務接入,數據同步問題也是,因為量大了,就容易堵塞通道。
數據中心服務架構剖析:每一個地區(qū)是左邊這樣一個架構,首先我的主要是邏輯服務,存儲是CKV,在邏輯上讀寫命令處理是分開部署的,代碼雖然是一起的。另外我做了快慢分離,同步轉異步,比如我要統(tǒng)計這個廣告的曝光點擊量,點擊率,第三方監(jiān)控(我在你這里投廣告你曝光了多少第三方需要統(tǒng)計一下)這些需求的性能實現(xiàn)是相對慢的,還有自己的一些統(tǒng)計功能,包括還有到同步中心的同步數據操作到另外兩地都是很慢的,這個絕對不能放在在線的寫操作里。 SSVR起到了一個隊列作用,它一部分是很快地接收數據寫入到隊列文件里去,另外再起一組進程讀文件,按后端服務的容量,往后隊列的形式,跟后端通道通信,對后端慢的服務也是按需調度服務的,只要跑得過這個流水產生的時間就行了。
架構里我們在統(tǒng)計數據功能實現(xiàn)上做了兩個獨立的通道,左邊DC上報這是騰訊公司級的組件層面做的一個,是基于用戶維度處理,用戶實際曝光和點擊哪些廣告,在羅盤系統(tǒng)上做出一個統(tǒng)計報表。另外右邊在隊列服務后面我們自己做了一個統(tǒng)計的數據,我們是根據廣告ID的維度做的,我們不想再處理很大量的問題,我們不關注用戶ID信息了,只關注廣告ID的維度,所以就可以上一些取巧的數據合并操作,數據量、計算量減少顯著,很簡單地數據統(tǒng)計就可以把這個報表生成。兩個通道兩個獨立邏輯,兩個通道得出的數據是一致這個報表的數據就是很準的。
***講一下右邊數據中心的異地同步方案。先對比一下通常的功能產品的模型,一般都是三地讀一地寫,比如你要看照片三地都可以看,你要發(fā)表一個照片一定要先接入到深圳收歸寫操作,然后再同步到上海和天津,這樣設計比較簡化,要考慮成功率去重試、時序性等,同步服務哪個數據失敗了要重試,一定程度會堵塞通道,還比較難避開這個問題。而在這個廣告系統(tǒng)里一定是要多讀多寫的,如果按這個常規(guī)方案會出現(xiàn)一個問題:用戶在上海點了一個廣告,本來當用戶第二次請求已經過來了,不該出現(xiàn)廣告了,但是還出現(xiàn)了,因為數據還在深圳往上海趕的路上。所以需要在本地直接寫好數據,所以我們只有選擇三地寫三地讀的方案,而這就要在同步中心建六個通道,比一般的產品投入量會大很多。所以我們要考慮如何簡化設計。廣告系統(tǒng)強調的是實時性、對數據的三地一致性和時序性要求并不強烈。所以根據這個我們大膽做了一個不做堵塞通道的一個同步邏輯,而且我們同步的數據只同步一些增量動作信息,比如我在深圳點擊一個廣告,我并不告訴你深圳存的是什么,往上海天津同步的就是告訴有這個動作發(fā)生,由每個城市的被你的服務自己決定如何改寫數據。因為很多渠道的接入比例和異地方案不一樣,所以在這個設計上,***深圳上海天津的數據總容量和用戶key下面的value其實都不一樣。容災方面假如通道有一些故障都斷的情況下,短時間斷了會形成三個“孤島”,三個“孤島”的***的問題是假如用戶在上海點了個廣告,下一次他又去深圳了,這個廣告就會被看到了。我們敢這么設計是大膽地嘗試,基于接入方式不會這么頻繁的變動的假設,我們有去實際模擬驗證一下,這樣的用戶按我們的統(tǒng)計,一天影響量才萬分之五.而要發(fā)生這樣一整天的故障,本來在騰訊也不常見,有這樣的故障,我們的平臺肯定已經做了其他的接入服務的調度容災方案,例如當初的天津大爆炸,我們很快就把服務流量切走了,不會讓用戶進入“孤島”。
平臺海量服務運營能力,首先是監(jiān)控能力,接口級別監(jiān)控,實實在在統(tǒng)計他的成功率和延時;用戶端是監(jiān)控,真正看你廣告拉出來的延時,還有廣告數據監(jiān)控:廣告有沒有按時出現(xiàn),有沒有點擊率符合預期。其次是服務容量,不考慮研發(fā)bug的情況下,我們的服務都定型后,所謂質量就是個容量問題,容量夠了質量就好,容量不夠質量就不好。容量對變化無常,這是廣告系統(tǒng)會遇到的問題,廣告計算的負載波動比較大,特別是平臺類型的廣告系統(tǒng),不像效果性廣告可以保持平穩(wěn)的廣告輸出量,特征是比較平的,我們這兒不一樣,比如手Q的banner有廣告沒廣告對你的系統(tǒng)有一個明顯的影響的,還有每個廣告的計算需求都會不一樣,例如是否定投計算是否驗證曝光數據等,希望云計算的彈性能力來做這個事情,但是現(xiàn)在的技術發(fā)展情況下要快速應對這種非常突然的負載變化時候,服務質量不抖動是很有難度的。那我們能做的就是,對未來要承擔的負債有一個預警,你就要去算,因為廣告主都會有提前量,比如下午的廣告上午就投了,不會馬上生效,總有一個時間去檢測我的負債是否足夠??偙仍谥苣┕?jié)假日突然發(fā)現(xiàn)負載不行了,措施不及要強。另外還有是做高性能,性能足夠我就可以在設備需求不大的情況下,留夠5到8倍的buffer,如果性能不行,同樣的buffer需要的設備數量就巨大了,運維兄弟的壓力就會很大。 性能方面很多常規(guī)的優(yōu)化的手段都有做,例如盡可能的緩存,和對應的淘汰邏輯,微線程的方式提供服務,堅持業(yè)務和廣告邏輯解耦,避免json協(xié)議編解碼,還有各種分離部署,避免一些服務抖動毛刺,例如數據中心的讀和寫以及回收多個命令字就分開服務,為了避免有些廣告可能突然間會量上來,有一些代價大的操作會給代價小的服務帶來不穩(wěn)定表現(xiàn)。容災方面,盡量設計無狀態(tài)的服務,那么結合L5負載均衡避開單機故障印象了,我們支持城市級別容災。值得強調的是抓細節(jié)吧,所謂容災,其實一些很關鍵的服務,我們總是可以覆蓋住的,但是實際檢驗起來讓你容災難以為繼的可能都是一些細節(jié),所以重在細節(jié),找短板。
下面部分再講一下廣告系統(tǒng)ROI優(yōu)化之路,這是我們走過的彎路。首先在ROI優(yōu)化前先要找準自己的瓶頸,我們的廣告數量級并不大,因為都是大業(yè)務的需求,可能廣告里就五個六個,不大于十個的廣告,但是效果廣告系統(tǒng)的廣告數據量是很大的,成千上萬的,甚至會經過初選、試選,算法復雜程度都不一樣,很多事情可以做,他可以做到千人千面。而我們需求量也不穩(wěn)定,所幸的廣告質量是可控的,因為廣告主離我們比較近,我們了解他們的需求?;谶@個前提,我們去設計適合咱們的ROI策略算法。
ROI提升實踐三種嘗試
***種是最開始走的彎路,有用戶進來通過各種方式查體的數據查在線的優(yōu)化,會發(fā)現(xiàn)就算你知道用戶喜歡哪一類廣告,但是你現(xiàn)在的庫存里面是沒有這類廣告,你沒辦法的。同樣一個項目他的廣告通過更多渠道去做他,可能這個廣告的用戶群并沒有在這個渠道上投,他去了另外一個渠道也可以做,廣告主來說他投放的代價是很大的,因為每個投放會帶來開發(fā)成本和投放成本,因為每渠道都是不一樣的。第三是非常有用的方式,我還是把渠道流量給一個項目,但是你不能再用一個廣告了,必須要設計多個廣告進來自己跟自己競爭,不同點在于廣告A投的是這個用戶群,廣告B投的是另外的用戶群,或者設計多個廣告圖。讓用戶點擊數據說話,技術上等待二三十分鐘就可以選出來優(yōu)劣,讓點擊率高的廣告生存下來,這個策略最直接的作用就是起到廣告主和用戶間的溝通橋梁,你做的工作好壞用戶會給你反饋,這個是刺激到廣告主你要去用新做一個廣告,其實很多廣告投放也很有門道的。有了這個反饋廣告主會更善于利用流量,ROI提升落到實處了。
ROI另外一些很重要的功能點就是負反饋。我們分析過,有的人看廣告七次都不會點進來,你給他投放再多次或者其他類型的廣告他也不會點,他選擇性地忽視了,這部分人群不要給他出廣告,對他來說他體驗也好了,對我們來說我們收益上也沒什么損失,還減少了騷擾。還有是頻率限制,流量出來后并不是馬上給它消耗完,平穩(wěn)地在一天或者更多天消耗完。甚至發(fā)現(xiàn)一個偶然的好處,第三方投放的時候,因為他們往往不太知道Qzone流量的威力,經常網站頂不住,等到網站頂住了的時候,流量卻消耗完了。雖然廣告主不知道我們Qzone的流量有多厲害,但是他肯定知道他的網站可以頂多少訪問量,按需做頻率限制就做好了廣告的轉化體驗。
還有一個是Qboss人群分析統(tǒng)計,你投完之后我們可以測試這個tag組選的好還是不好,你選一組tag后,我們統(tǒng)計出曝光和點擊人群里,符合這個tag的占比多少,如果兩個持平了,可能說這個tag在廣告受眾里不是很明顯的東西,如果點擊比例高于曝光的,這就是很正向的tag,反之就是負向的。通過這個工具,廣告主就學習到了經驗,以后投這類廣告的時候你就是知道優(yōu)先要投哪部分人群。
ROI提升的事情我們是去年12月之前結束的,看各渠道的點擊率提升,有的是百分之十幾,有的是百分之三四百,這個是符合預期的,我們提供的只是一種工具,一個反饋渠道讓廣告主得到信息和經驗。你自己廣告主的優(yōu)化必須是你自己想辦法做的事情,做的好就是百分之四百,做的不好你還是百分之十幾。
系統(tǒng)架構設計心得
我們技術價值一定要體現(xiàn)在業(yè)務上面,我們開始做的廣告系統(tǒng),比如今天講的聽起來很樸素的,但是他能解決業(yè)務問題就是一個好的東西。還有是職責識別,我們把一個廣告系統(tǒng)分成3個大的方向,每個大的方向有它的職責范疇,抽象一下也就能滿足大系統(tǒng)小做的要求了,一個復雜問題簡單化,比如用戶中心這塊兒你只需要給我判斷這個用戶是不是用戶集的,別的問題都不用管。再是抽象一個層,可以解決很多需求問題。善于在存儲上做性能提升例如redis的成功,邏輯很簡單,性能也非常好,包括我們剛才介紹的好友參與系統(tǒng)都能很快解決問題。低成本的優(yōu)化思路上盡量優(yōu)先考慮業(yè)務場景特點的利用,如果成本高,首先可能考慮到存儲的介質優(yōu)化,看看有沒有一些數據協(xié)議壓縮等等手段,可是收效不一定好,我建議大家還是從業(yè)務家度上考慮問題,可能他給你帶來的是上十倍百倍的成本節(jié)約,廣告系統(tǒng)就大量利用廣告短期時效性的特點去做了很多成本節(jié)約。盡量做無狀態(tài)的服務,能夠保證你的負載均衡一致性,容災也方便。還有各種部署的分離,在一些小的系統(tǒng)里這個有點多余,但是在海量系統(tǒng)里這個還是很有必要的。***我們所有的架構設計都是依賴自己的數據方面經驗的,但是在你上線前或者后一定要通過數據驗證它。例如我們設計的異地同步方案,容災的考慮就有數據調研,上線后也去驗證了,這樣我們才能讓這個架構繼續(xù)工作,也有利于后續(xù)的經驗積累。