百億級實時消息推送的實戰之道,與王者榮耀一班車就是這麼穩!

要說如今市面上最火爆的手遊,莫非擁有兩億註冊用戶的王者榮耀了。據悉,王者榮耀的滲透率高達22.3%,這意味着每7箇中國人中就有一位是王者榮耀註冊用戶。衆所周知,手遊App對推送實時性和精準性要求很是高,而王者榮耀這種日活躍千萬級的應用對推送的要求就更高了,下面咱們來看看王者榮耀背後的信鴿推送是怎麼應對挑戰,作到海量、實時和精準推送的。linux


2017年7月7日-8日,ArchSummit全球架構師峯會在深圳召開。ArchSummit全球架構師峯會是InfoQ中國團隊推出的面向高端技術管理者、架構師的技術大會,展現新技術在行業應用中的最新實踐,其中超過上百位技術專家,千名技術人共同參與,包括海外的facebook、ebay、hulu,國內的BAT、YY、京東等,羣英薈萃,精彩紛呈。

騰訊移動推送(信鴿)高級工程師甘恆通在本場架構師峯會上分享了《騰訊移動推送(信鴿)百億級實時消息推送的實戰經驗》,解析了信鴿實時精準推送系統的演進與實踐。算法

信鴿的挑戰

應用的用戶的生命週期來講分5個階段,即用戶的獲取、激活、留存、傳播和收入,信鴿的消息推送是觸達用戶,提高留存的重要途徑。sql

信鴿平臺現已服務於數萬的App開發者,日推送消息數60億,推送支撐能力超過百億;而精準推送是有效提升消息打開率的手段。信鴿的實踐中案例數據代表,精準推送的平均CTR是全量推送的4倍數據庫

那麼,如何實現海量數據的壓力下,知足實時、精準的推送要求,這裏有很大的挑戰。緩存


這裏咱們主要討論的是對於信鴿後臺的挑戰,主要有這三個關鍵字:海量、實時和精準。

海量是指,信鴿終端併發長鏈接是數千萬,日推送量也有百億的量級,服務於不少大客戶,如王者榮耀,日活躍數千萬,其推送量可想而知。性能優化

另一些特殊行業的App,也有特別的推送訴求。好比資訊類的應用,時效性要求很是高,須要每秒千萬級的推送速度。網絡

而另外一些應用則須要在達到運營目標的前提下,但願儘可能減小對用戶的騷擾,即精準推送。數據結構

信鴿的應對之道

對於信鴿面臨的挑戰,咱們作了哪些解決方案?
首先信鴿是一個免費的運營工具,成本是咱們這邊一個很大的須要考量的點:一方面,須要提升設備資源的利用率,能夠經過一些虛擬化的方式來解決;第二方面,咱們要深刻挖掘單機的性能。多線程

對於單機性能的優化,有4個方面,從下往上看是硬件、操做系統、協議棧、架構。架構

一、 操做系統優化
先看一下在操做系統這個層級是如何對海量併發長鏈接的接入進行優化的。這裏主要挑戰是在內存,經過slabtop命令能夠看到當前系統內存分配的狀況。從這一欄能夠看到,當咱們構建了大概200萬長鏈接的時候,整個系統的內存基本上已經滿了。對於長鏈接的內存使用,會消耗在這6個數據結構上。

咱們深刻分析這6個來自epoll模型和內核TCP協議棧的數據結構。對於epoll模型,底層實現是一個特殊的文件系統,epoll文件的內容主要是保存了一棵紅黑樹和就緒的被偵聽文件列表rdllist,紅黑樹的節點是被偵聽文件對象。epoll主要提供了三個API:epoll_wait、epoll_create、epoll_ctl。當咱們經過epoll_ctl把一個文件加入到epoll的時候,會建立兩個數據結構epitem、eppool_entry,epitem關聯到被偵聽的文件fd,eppool_entry保存了事件就緒時設置rdllist的回調函數ep_poll_callback。咱們從另一個鏈路看一下網卡的收包流程,當數據包過來的時候,網卡接收完數據會產生一個硬中斷,數據經過DMA拷貝到內存。系統經過軟中斷守護進程,調用網卡的驅動來完成數據包的解析並最終調用poll方法。poll方法會回調設置好的ep_poll_callback,即把fd掛到rdllist中,當調用的epoll_wait時候,便可獲取到就緒的fd集合。


對於海量的併發鏈接,主要經過調整操做系統的配置來解決。信鴿使用了公司自研的tlinux 2.0,系統對於內存這一塊也作了比較多的優化,具體的配置參數以下,能夠看到,主要也是一些epoll的限制和TCP的內存的限制。

二、 Server框架優化
看完操做系統層級的優化,咱們再來看一下另外一個主要性能優化的點——server框架。信鴿對於關鍵的接入層server使用C++語言進行開發。好的server框架主要有兩個要點,1是對底層RPC通訊的良好封裝,使得開發只須要關注業務邏輯代碼的開發,2是高性能,框架對消息處理CPU消耗盡量少。經過Intel® VTune™ Amplifier這個工具咱們能夠對server框架進行性能評測,這裏列了兩個框架。左邊這個框架能夠看到把不少CPU都浪費在消息的內存拷貝,同時對消息的處理進行了過多的封裝。對於右邊的框架就作得比較好,對於框架的問題就不存在了,主要是操做系統自己的消耗,還有協議棧的消耗。這部分對於有更高的要求來講,還能夠進行深度優化。這是咱們後臺選用的框架,主要實現的要點有三個,第一是池化技術、第二是協程模型、第三是無鎖框架。這裏的Proxy主要用於接入網絡的請求,具體的業務邏輯代碼是放在Work進程裏面處理。整個框架作了一個通用的抽象,將一次數據請求主要分爲數據接收、數據路由、最後是具體的數據處理。數據接入進程和具體數據處理進程,經過無鎖的共享內存來通訊,這樣就避免了不少沒必要要內存拷貝和消息編解碼操做。

對於處理業務邏輯的工做進程,比較常見的有三種模型,第一種是進程同步模型,數據進來之後,由獨立的線程進行處理,優勢是代碼實現比較直觀,缺點是處理海量併發用戶請求的時候,操做系統對多線程的切換會成爲一個主要的瓶頸。第二種用得比較多的是異步事件驅動模型,由epoll進行事件的偵聽,經過一些狀態機來驅動業務邏輯代碼的執行,優勢是性能較高,缺點是當業務邏輯分支多的時候,代碼很是難維護。咱們這邊是採用協程模型,協程和線程和相似,它跟線程不一樣的是,線程的切換和調度須要本身來實現,協程模型能夠採用同步的思惟進行代碼開發,又具備異步模型的高性能,協程切換優化的點是,經過彙編的方式,直接把相關寄存器中的值保存在內存,來進行上下文的切換。

三、 協議棧優化
下面咱們看一下協議棧的優化。這裏的協議棧主要是指linux內核TCP協議棧。linux內核的協議棧主要問題是相關Socket的方法都是系統調用,須要從用戶態切換到內核態,數據從內核空間到用戶空間也須要進行額外的內存拷貝操做。業界有一些開源的用戶態TCP協議棧,能夠解決這兩個問題。使用用戶態的TCP協議棧須要優化的點是相關的接口和系統自帶的Socket接口命名不一致,直接使用涉及到大量代碼的修改,咱們怎麼樣作到在不修改代碼的狀況下用TCP協議棧呢?這裏是經過Hook機制,攔截相關Socket系統調用,dlsym符號解析返回自定義的Socket方法。
四、 硬件性能挖掘


下面咱們再看一下單機性能優化的最後一個點——對於硬件性能的挖掘。硬件性能的挖掘,主要是善於利用Intel CPU的指令集。能夠拿咱們常用的CRC32操做來舉例。通常的CRC32實現是根據算法定義來執行字節轉碼操做,而Intel提供了一套SSE4.2的指令集,它裏面包含CRC32的方法。咱們能夠看一下35W次計算二者的耗時對比,直接用Intel的指令集比通常的實現方法快6倍。

小結:性能好,推送才能頂住海量信息的壓力,支撐公司內外業務核心,提供強有力的通道支持。

實時方案的構建

對海量設備進行實時推送主要的解決方案是針對推送的場景優化存儲結構,同時將單個推送的RPC節點間調用轉換成分佈式的批量位圖運算,優化Android終端長鏈接,接入集羣分多地部署,作最近接入,和APNs的交互使用HTTP/2協議,對無效的token自動作數據清理。


咱們這裏舉一個具體的場景來講一下倒排索引是如何應用到實時推送中的。好比一個應用對在廣東的男性用戶進行一次推送,會通過一個這樣通用的推送流程:一個推送的任務到達一個調度的節點,決定是否下發推送任務,若是下發,則會通過目標人羣的檢索,篩選出男且是廣東的用戶,接下來進行通道檢索,信鴿這邊既有自建的通道,也有廠商的通道,用戶在推送的時候,他可能以爲廠商的通道更加穩定、更加高效,這個時候他能夠選擇對於華爲設備走華爲通道、小米設備就走小米通道,對於其它的設備就走信鴿自建的通道。下一步就是地域檢索,信鴿這邊的設備是就近接入的,咱們在全國部署有這幾個集羣,分別是深圳集羣、上海集羣、天津集羣和海外的HK集羣。這裏選擇了廣東的用戶,因此選擇深圳集羣。對於一個傳統的系統來講,一次推送能夠這樣實現,一個應用下的N個用戶的推送,轉換成N次RPC節點間調用,人羣信息、通道信息、地域信息分別保存在Mysql或者Nosql數據庫中,每一個RPC調用,須要到數據庫裏面檢查一下他是不是男的,是不是廣東的用戶,再看一下是否是華爲的設備或者小米的設備,斷定完以後要進行地域的檢索,看看接入的是哪一個集羣。整個流程下來以後,要通過大量的數據庫操做,才能完成一次推送。

可是通過倒排索引的構建以後,全部的數據均可以放到內存中。好比男性人羣,能夠構建一個bitmap,小米的通道也是一個bitmap,華爲的通道也是一個bitmap,不一樣的地域分別是不一樣的bitmap。當一次任務下發的時候,對bitmap進行一些&操做,就能夠把最終須要推送的人羣下發到相應的接入機中,整個過程能夠作到ms級別。對於推送下發整個流程,檢索是一方面,另外一方面還須要查詢路由信息找到終端TCP長鏈接的接入機,這些路由信息包含接入機的編號、進程的編號、長鏈接socket fd的編號,用一個long數據類型便可保存,全部的路由信息保存在分佈式的Nosql內存數據庫中,整個推送流程只有接入機的路由須要進行數據庫的查詢,結合本地的緩存,能夠作到kw/s的推送下發速度。

精準推送的構建

信鴿的推送系統主要分爲三部分,第一部分是數據、第二部分是具體的系統實現、第三部分是具體的應用。


具體的應用有這三個:實時推送、推送助手、ABTest。推送助手和ABTest的做用是更好地幫助用戶使用消息推送來進行產品的運營。好比推送助手,對於不少運營人員來講,可能沒有相關的運營經驗,對內容的管理,他可能只大概知道須要推送的目標羣體,可是他對推送文案不知道若是編寫會更好,這個時候咱們後臺會對歷史的推送進行數據的收集,對文案和推送的效果進行關聯性的分析,當他選擇一個推送場景的時候,咱們就會把一些文案的樣式和關鍵詞給到他,讓他本身組織出一個更好的推送的文案。另一個是ABTest,用戶本身手裏有幾個文案或者目標推送人羣,當他不肯定的哪一個更合適的時候,咱們給他提供ABTest的能力,從目標推送人羣中抽取部分測試用戶,多個文案通過實時推送,在幾分鐘的時間裏,把推送的效果即點擊率反饋給用戶,系統自動或者由用戶選擇一個最佳的推送文案或者是一個最佳的目標人羣對剩下的用戶進行推送。

下面看一下系統的實現,主要分實時和離線。離線部分主要是用來進行人羣的挖掘。對於精準推送來講,它的核心是根據應用運營的目標將消息推送給匹配的目標人羣。應用的運營的目標通常有提高用戶活躍度,潛在流失用戶挽回,提高應用收入等,不一樣人羣的挖掘方法可能不盡相同,但流程基本一致,通常會分爲數據的準備、模型的構建、預測結果、輸出。

咱們這裏舉一個實際的潛在流失用戶人羣挖掘的例子。咱們想預測一下這個應用裏面可能有哪些人是會流失的,這樣應用能夠針對這部分人羣作一些挽留的推送。原始數據保存在HDFS或者TDW裏面,通過數據加工之後,把用戶可能流失的一些特徵給提取出來,好比說有首次註冊的時間、每日啓動的次數、每日的活躍狀態和最近登陸的時間。特徵提取後有兩條路徑,一是要構建一個潛在流失用戶預測的模型,二是在模型的基礎上進行潛在流失用戶的預測。對於模型構建部分,須要結合真實的流失狀況和特徵,做爲訓練的樣本,通過算法模型的訓練以後,咱們就獲得了一個潛在流失用戶預測的模型。對於天天新增的數據,咱們也是通過特徵提取以後,把數據輸入這個模型裏面,就會獲得一個具體的預測結果便可能會流失的人羣集合。對於算法模型,咱們這邊主要用了一些機器學習裏面的統計學習的方法,沒有用到一些如今比較火的深度學習的方法。由於咱們在實際進行訓練的時候發現當咱們的數據樣本很是大的時候,用通常的好比C4.5決策樹模型,經過一些斷定規則,就可以知道用戶是否流失,或者是貝葉斯,經過特徵類別的條件機率分佈預測是否會流失,採用這些模型召回率能夠達到0.76和0.89的水平,已經知足咱們的應用場景,因此沒有采用計算複雜度更高的深度學習的模型。

實時效果評估
信鴿最新更新的實時效果功能,爲用戶提供了推送效果的實時統計。面對百億級推送的壓力,實時統計也會佔用很大的計算資源,那麼信鴿是如何實現這一功能的呢?
通常推送的效果評估主要看CTR,可是CTR可能對於一些用戶來講,不能反映他的運營目標,他可能更關注的效果是我作了一次推送,用戶有沒有到達個人目標頁面,或者說推送了正在進行促銷的通知,有沒有更多人進行下單購買。這些場景能夠經過在前臺給用戶管理推送效果跟蹤配置的方式來實現。用戶每次推送以前,能夠指定推送效果如何評估,這裏多是一些目標頁面集合的瀏覽pv或者自定義事件的uv,系統把它轉化成一個配置文件。當他進行推送的時候,咱們就會把配置文件下發到統計系統裏去。當執行推送完以後,應用的用戶就會產生點擊、註冊、瀏覽的行爲。這些數據到進入到系統的時候,主要會作兩部分的操做,第一部分是根據推送文件指定的方法進行數據的抽取、過濾、轉換、加載並更新相關的倒排索引數據,當真正須要指標輸出的時候,咱們會有一個管理的節點,進行計算規則的下發,好比說點擊的用戶裏面有多少是男的,檢索之後進行一次bitmap的&操做,就能統計出有多少用戶了。數據會實時刷新到Redis存儲中,應用開發者在前臺查詢結果的時候,咱們就會把這個結果反饋給用戶。

能看到這裏的都是真愛!今天的乾貨分享就先到這裏~

本文的姊妹篇《百億級消息推送背後的故事——來自於infoQ的前方報道》將於下週推出,敬請關注哦!

聯繫咱們:

若是您但願試用或者體驗信鴿推送,請訪問信鴿官網接入試用。

若是您對該功能有疑問、或者在使用中遇到了困難,歡迎您聯繫信鴿官網在線客服,或者發送您的問題郵件至:dtsupport@tencent.com

商務合做或業務諮詢,請聯繫如下郵箱:data@tencent.com

相關文章
相關標籤/搜索