作者簡介:沈冠璞,熊貓TV高級應用開發工程師,近7年后端開發經驗,曾任職新浪微博、360等互聯網公司,負責短鏈接、微博Card對象、網游頁游平臺業務。對高并發海量數據業務設計有豐富經驗;經歷熊貓TV從0到1 海量PV和存儲的快速擴張發展場景,有大中型互聯網網站高可用設計架構經驗。在MDCC 2016上,沈冠璞將結合自身經驗,解析在熱門時段大主播高峰值情景下優化禮物系統技巧,帶來題為《百萬彈幕下的直播禮物系統》的分享。
本文為《程序員》原創文章,未經允許不得轉載,更多精彩文章請訂閱2016年《程序員》
2015年開始的百播大戰,熊貓TV是其中比較特別的一員。
說熊貓TV是含著金鑰匙出生的公子哥不為過。還未上線,就頻頻曝光,科技號,微博稿,站上風口浪尖。內測期間更是有不少淘寶店高價倒賣邀請碼,光內測時用戶注冊數量就達幾十萬,火爆程度可見一斑。筆者作為寫下熊貓TV第二行代碼的Coder,見證了熊貓TV成立以來的風風雨雨。直播技術坑不少,本文簡單揭秘熊貓TV這一年的技術架構演進,分析各個階段面臨的主要問題和應對方案,給大家做直播系統提供一定的參考。
熊貓架構 0.1- 來不及了,老司機快上車
這個階段最大的目標就是按預期時間上線。
圖1 項目規劃時間表
組團隊不表,10人左右的Web團隊,從接需求,到上線,我們用了不到三個月。
這個階段面臨的最大難題:兩個月就內測!
怎么辦?找老戰友刷刷刷!花錢買買買!作為一群經驗豐富的老司機,我們用買零件翻新車的方法。網站內測公測階段,需要滿足用戶登錄注冊、關注主播、看視頻、發彈幕、加房管、領任務、送免費竹子等核心功能,采用了復用模塊+主業務全新開發的策略。
復用模塊
復用模塊得益于團隊的前360技術背景,根據直播秀場類項目上的技術積累,利用PHP框架Pylon、發版工具Rigger,在老戰友的幫助下,重新搭建了一套QBus消息組件,長連接系統,改進的Redis、MongoDB和MySQL集群,視頻云服務,敏感詞服務,搜索服務,這個項目才有了強大的基礎支撐,才有可能在兩個月時間就上線。
視頻模塊——從新搭建視頻云,RTMP推流拉流,接入三家CDN作為互備。這其中需要自己實現統一調用接口和服務,方便切換CDN: 推流地址、拉流地址、轉碼規定、開播斷流回調、一鍵斷流、連接數查詢、流截圖、直播時長查詢。基本上每個接口都很重要!例如一鍵斷流萬一失效,則可能面臨停業整頓風險;人數不準,主播掛人氣刷榜,則可能導致不公平競爭而影響平臺的體驗與口碑。
分布式基本組件:復用Syslog-ng日志收集系統、Kafka消息隊列QBus、MySQL主從庫、Redis主從庫、MongoDB、SSDB大容量存儲。
長連消息:單機百萬長連,支持千萬用戶同時在線,性能夠用,保證聊天彈幕穩定性。
圖床:很重要的一環,房間截圖,用戶頭像。
CMS系統:配置各種推薦位,直播間的CDN調度。
主業務開發
雖然是個新項目,我們并未做一個一籃子應用,把所有接口放在一個項目,而是按功能模塊分好項目,每人負責一個,對主站panda.tv項目提供內網API,部署方便互不影響,開發效率也比較高。
Flash播放器:ActionScript開發、視頻播放、彈幕展現。
主站pandaren:頁面展現,各個子服務的串聯整合;Daemon Worker負責截圖更新。
用戶體系ruc:用戶注冊登錄、用戶信息。
房間服務vill:包括房間信息、房間列表、更新房間人氣。
關系服務uprofile:包括訂閱關系、觀看歷史、主播申請、內測邀請碼 。
數值服務count:竹子贈送、主播身高、用戶經驗。
消息服務homer:用于房間劃分,長連Session ID和熊貓TV房間用戶ID的轉換。
權限系統buffon:房間管理、房管、黑名單。
任務服務bee:新手任務、觀看定時獎勵。
主播直播時長bloodstone:主播固定工資需要按每月直播時長計算。
架構哲學和設計
熊貓TV架構第一原則是高可用
網絡:需要應對國內復雜的網絡環境,使用內網光纖互聯的多IDC來覆蓋多運營商。
資源:DB和緩存都是集群化,配置Virtual IP方便切換。
隔離性:不同業務不同機器,防止雪崩效應;核心和非核心業務隔離,流量扛不住情況保重點業務。
降級:從Nginx和API層設置接口開關、Cache開關、DB開關,出問題一鍵切換。
超時控制:主站每個依賴業務設置5秒超時,并有報警和錯誤日志。
異步:用戶不關心實時結果的大寫入量業務使用異步方式更新,提高核心服務性能。
監控:服務器錯誤設置log監控、接口監控報警,隨時處理線上異常。
架構目標(SLA)
根據以往新項目經驗,預估支撐1000TPS ,百萬日活用戶,單房間10萬左右在線彈幕;平均響應時間在100ms,99.9%在1s內;千萬級別數據量;99.9%的可用性(全年宕機在9小時以下)。
架構選型
四層負載均衡:LVS,目前基本是業界標配,如果使用云服務的話可以用廠商提供的負載均衡,如阿里云SLB和亞馬遜ELB等,這種第三方依賴都需要嚴格引流壓測確認DB層、緩存層、Web層是否
有坑;
Web層:Nginx+PHP-FPM,開發迅速,適合團隊技術現狀,但需要針對服務器,做一定的調優配置。
緩存層:Redis主從庫、SSDB大容量存儲,會在各個業務塊兒使用,增加系統性能。
存儲層:MySQL主從庫存儲重要業務數據,屬性變化不大。MongoDB數據庫存儲字段不固定變更較多的數值明細記錄。SSDB存儲觀看記錄關注等列表較長,且性能要求較高的數據。分表分庫上考慮用戶注冊量和主播播放頻率,用戶中心、主播播放時長采用了按用戶ID Sharding和 按年Sharding兩種策略。業務初期暫時沒有分庫需求。
消息隊列:實現業務解耦,使用當前較流行的Kafka隊列。
設計實現
機器配置采用6核16G的虛擬機。服務部署單獨的XEN虛擬機集群,互不影響,進行多機房互備,機房間光纖專線內網互通。
圖2 整體架構
120臺虛擬機分給十多個業務,主站用了40+,三個IDC——電信聯通移動同時使用,流量大的主機房在電信,其他兩個機房部署Redis、MySQL從庫,寫都在電信。預估的注冊在線人數百萬級,QPS萬級。接口使用PHP-FPM對外服務,單機性能平均500QPS+,內測邀請制,內測一個月期間十幾萬人涌入,解決了一些小Bug,然后大家頗有信心迎接公測。
熊貓架構1.0——一只穿云箭,千軍萬馬來相見
這個階段屬于填坑,最主要目標是網站穩定可用。雖然每個服務都有多機房災備,微服務化也做了較好隔離,但0.1不到一個月便宣告夭折,我們低估了熊貓TV的明星效應,低估了黑色產業鏈的薅羊毛能力。公測一開始,熊貓就炸了(水友術語,指網站不可用)。
重點問題
網站首頁和房間頁不可用,無法進房間看視頻;
已經在直播間的用戶直播卡、彈幕卡、彈幕發不出去。
分析:網站因注冊和用戶信息、首頁、房間頁訪問量過大導致FPM進程跑滿,接口和模版渲染耦合,本身占的調用時長就會過多,服務間斷性不可用,Redis緩存首頁推薦位和用戶信息只需幾百MB,但連接數過多,內存占用到10G+,導致Redis響應緩慢不可用,垃圾號瘋狂注冊,第一天便破百萬,用戶中心出現服務異常,緩存命中率低,進而雪崩。
聊天彈幕爆發,時段非常集中,每日晚8點到凌晨2點為網站高峰時段,如圖3所示。
圖3 某個Redis端口QPS情況
這些也是直播網站會一直面臨的核心穩定性問題,針對這些問題,大架構框架沒有變動,加班加點,兩周時間就上線了新一版架構優化。
高性能
主站重點接口Lua化:消息限制發送頻率,并改造為Lua接口,十倍提速,避免占用主站PHP-FPM資源;贈送竹子也改造為Lua接口;用戶中心取用戶信息也改為Lua接口,直接從緩存讀。
用戶ID發號器改造,不依賴MySQL自增ID,提高并發性能。
高可用
首頁和房間頁靜態化,Worker機抓取生成模版,分鐘級別更新,然后rsync到各個服務器,Nginx直接讀HTML文件生成首頁、房間頁,其他個人動態信息都走Ajax請求,保證不會出現白屏情況。
重點Redis增加到10+ Slave,Slave間樹型同步,葉子節點從庫從上級從庫同步,避免一主多從傳輸數據延遲。從庫的增加也避免主庫網絡負荷和連接數過多,導致響應延遲過大,服務不可用。
核心業務增加部署服務器,應對集中峰值訪問。
其他問題解決和功能完善
安全性上:所有80接口做XSS校驗,CSRF token防范,對接口做幾十道安全檢測,防止被拖庫,防止Cookie被盜用;反垃圾反盜號反外掛:含敏感詞聊天信息過濾,垃圾IP封禁;注冊和任務都增加圖片驗證碼,識別機器刷用戶刷竹子;房間人氣值采用復雜策略,用算法綜合判斷確認合理性,防刷防掛;主播審核更加嚴格,身份證銀行卡姓名等信息都要求錄入,可以追究責任到真人,甚至有視頻驗證,嚴防色情內容。
功能上:建立游戲娛樂戶外等分類模塊,運營自助增加分類;部署并自行運維第三方搜索服務,支持主播昵稱、標題、房間號等維度搜索,過濾直播狀態、主播地區、封禁狀態等條件;禮物系統抽獎投票等系統上線,增加主播收益渠道,增加互動。
優化效果:全年未出現過白頁、首頁不可訪問情況,支撐千萬級PV,百萬級日活,單房間最高達到百萬級在線,視頻流量近TB級;接口平均響應時間20ms左右,99.9%在1s內;各個系統數據存儲量破千萬,MongoDB、SSDB等大容量庫很好地支持了業務。
熊貓架構 2.0 - 新視界,大不同
到2.0階段,初期的刷臉靠戰友幫搭建基礎服務和買第三方服務,已不能精細化、定制化地支撐業務快速發展,而此時人員配置也開始完善,熊貓TV開始了全新的2.0自主研發階段。
本階段也屬于穩步發展階段, 最主要的目標是視頻流暢清晰、彈幕互動效果穩定。
視頻優化
接入決策上,接入更多家CDN,并對CDN穩定性做指標考核和嚴要求:根據卡頓率、延遲時間、首屏時間、聲音視頻同步率等指標,結合運營經驗,創建了一套立體化多維度的CDN-SLA體系,決定給予流量多少,主播級別,主播數量。這樣也增加CDN的危機感,更好服務用戶。
視頻流調度互備上,如圖4所示。
圖4 視頻流調度互備上
主播推流區分默認配置和管理員配置,推向對他而言網絡狀況最好的CDN,CDN自身節點實現各地的復制,CDN之間實現推流互備,一個CDN掛掉,不影響使用,用戶根據PC或手機端區分,從對應配置的CDN拉流看視頻,從而實現最佳觀看效果,Web端用戶也可切換備用線路,當默認CDN出現問題,則選擇從其他家CDN進行拉流。
這樣就保證觀看的流暢和視頻的整體高可用。
全新開發長連接系統riven來提供彈幕服務
圖5 riven 整體流程
建立連接:
通過房間ID獲取網關IP;
根據網關IP建立長連接;
更新網關上房間ID和長連接的對應關系。
下發消息:
同步消息;
生成消息機房對其他機房進行同步;
同步消息的機房不在進行同步行為;
根據房間ID獲取房間所在的網關地址列表;
向網關列表下發消息投遞通知;
網關查詢本地房間對應的所有連接,并進行消息投遞。
使用Golang+Redis全新開發,對消息級別、消息發送和消息內容做了一定優化。級別上區分多種Level消息,在高峰期、網卡被打滿極端情況下,丟掉部分不重要消息;消息發送進行打包方式發送,一個房間的消息一次批量推送幾十條,減少TCP交互;消息內容去掉無用字段,減少長度,例如禮物消息一條減少了168字節,假設高峰期一個房間十萬人在線,一條禮物消息能節16MB,大主播房間按1000個禮物一小時算,能節省16GB流量,非常可觀,所以一定要注意消息內容的壓縮和縮減。
整體架構上的改變:一年以來用戶量爆炸式增長,達到日活用戶近千萬,PV上億,同時直播主播近萬間,流量峰值TB級別。技術人員也擴充了4倍,隨著王校長驅動開發、尹素婉驅動開發(尹素婉是韓國第一女主播)、PDD驅動開發(PDD是前職業選手,著名LOL主播,彈幕量大,觀眾百萬)等模式的驅動開發,熊貓快速步入2.0時代,技術架構也有了更穩固的改進,新的PHS(Panda High-Perfomace Service熊貓高性能服務體系)設計思路是增加架構層次,明確微服務邊界,基礎組件從外部依賴到內部自研,架構層次宏觀層面分為端、接入層、平臺服務化、中間層、基礎層五個層次。
圖6 架構層次
端
包括Web頁、iOS、Android、各種Pad端、網吧彈窗合作、電視盒子合作App、游戲主機合作App,從各個渠道擴展業務。
接入層
從大而統一的panda.tv分流出mall.panda.tv、roll.panda.tv、pay.panda.tv、open.panda.tv等,保證各個接入業務互相隔離。接入層stars.panda.tv、pandagirls.panda.tv嘗試使用NodeJS提供API,前端完全自行研發,提高效率,性能也比使用我們的Pylon-PHP框架提高了6倍左右,可以滿足當前流量請求。
平臺服務化
架構體系沒有太大的變動,主要采用Golang技術棧做了整體升級。流量突發時PHP-FPM子進程新增緩慢,多進程模型切換代價較大,不能較好服務高峰請求,緩存和DB連接池復用困難,我們重點業務從PHP遷移到Golang;部署上,依賴Nginx+LVS探活實現不停機熱部署;Gobase基礎庫,實現了一套特定業務場景Concurrent Map庫;實現了配置讀取模塊;對MongoDB Client進行了封裝,便于CRUD方式使用和對象映射;Redis連接池和CRUD操作封裝,業務不需要協議命令細節,而是正常Get(key)、Set(key)即可;數據訪問層結合配置服務封裝分片與路由來支撐容量水平擴展;封裝Log、HTTP請求和HTTP Param解析等基礎類。
通過對Golang半年的使用,我們建立了自己的一套技術開發體系:Gvt創建項目和管理依賴,Ansible管理服務器和分發部署,Postman進行文檔編排和代碼測試, Teamcity實現持續集成。
業務上,CDN調度項目TrafficCoop,高性能,靈活配置Web端和移動端CDN信息;API-Proxy項目 ,原生Golang Router,使用OAuth 2.0,提供對外網關,中轉內部服務;禮物系統全面使用Golang+Redis+MongoDB保證穩定性和高峰處理。新業務原則需要快速開發,性能要求較低的業務使用PHP,性能要求高的業務用Golang、NodeJS。
用戶中心則持續演進:支持FaceBook等賬號接入;電話語音驗證碼防外掛,異地IP重新登錄機制防盜,個人身份指紋識別,做到徹底防盜號。另外為提高接口安全性,解決DNS劫持等問題對服務HTTPS化,各業務根據需要跟Ops申請HTTPS證書或SAN(多域名)證書。
中間層改進
視頻效果優化:接入更多CDN廠商,進行評測對比,及時反饋問題,督促其合理設置緩存值,實現視頻播放流暢化。
Flash調整彈幕展現策略:實現既能有滿屏感,又不會因同屏彈幕過多卡住瀏覽器,達到觀看和互動的平衡。
文本反作弊:機器學習訓練房間彈幕內容,模型上對廣告、色情、敏感詞、黑白名單等進行打分評定。
增加圖片墻鑒黃服務:30秒刷新房間截圖,接入多家鑒黃API,合理評分,快速發現直播內容異常。
圖床自建:圖片存儲從Cassandra遷移到公有云對象存儲,節省運維成本,直接使用第三方CDN,加速圖片訪問。
基礎層
Kafka隊列自建:基礎組專人開發維護,更快更好解決問題;竹子經驗計數、用戶關系等從SSDB遷移到Redis Cluster,保證性能無瓶頸,數據量暴增無壓力。
Spark Streaming平臺搭建:彈幕內容分析與輿情,CDN質量實時監控,用戶行為實時感知。
另外一個比較大的架構變動是業務機房遷移。實現了DB遷移,公有云互備。二十多人演練數十次,按照兩頁的遷移清單,所有業務重新部署,DB重新導入,停機維護一整夜,所有服務從原有機房一次性成功遷移到兩個公有云上。
總結
熊貓TV架構改進思路是應對峰值流量高度集中的直播需求,總結幾條經驗:
不能依賴單個CDN。可自建,可用第三方,但中國網絡環境太復雜,必須高度重視容災。海外推拉流也需要十分關注。
彈幕消息一定要做策略優化。廣播蝴蝶效應明顯,峰值可能將機房整體帶寬打滿。區分彈幕優先級,做好降級預案。
提高金錢敏感度。直播網站由于有很清晰的變現模式,要嚴防褥羊毛,嚴防色情內容,火速響應監管,支付禮物交互一定是高可用、嚴監控。
N個大主播 = 半個網站峰值。必須考慮某些特殊主播的火爆人氣,做好視頻彈幕房間信息上的峰值應對。
熊貓TV因快速上線和爆炸式增長,從嚴重依賴外部服務,到自主自建核心業務,彎路走了不少,也對直播技術有了更深的理解,積累了豐富的經驗,技術團隊也從20人左右快速擴展到百人團隊,為熊貓TV在百家直播平臺中挺立飛奔奠定了技術基礎。未來我們會在以下方面繼續努力:
自助式運營處理:幫助運營自助處理問題,直接和CDN對接,幫助技術人員從簡單重復問題處理中脫身。
反作弊:基于大數據處理體系的用戶畫像、設備畫像、IP畫像、內容畫像,多維度構建反垃圾反盜號功能 。
長連優化:支撐千萬用戶在線的高并發實時彈幕和聊天。
禮物商城:優化計數對賬,冪等處理整個支付到特效抽獎、彈幕消息、消費記錄、統計等流程。
Golang、NodeJS服務化:替代性能較差需要各種優化的PHP,服務端接口全面Golang化,前端也在合適的場景使用NodeJS提高服務性能。此外需針對KV存儲做value壓縮,節省流量,提高接口速度。
數據挖掘和機器學習:渠道分析、用戶分析等便于產品和高層決策,甚至開發出機器人主播互動。
推薦:在綜藝化娛樂化多元化的內容基礎上,個性化推薦用戶感興趣的直播內容。
搜索:自建搜索,從用戶維度、聊天維度更好服務用戶。
日志收集分析:高性能日志方案探索,更快更迅速發現業務問題,分析流量變化。
廣告系統:友好娛樂化的廣告展現,精準推送,嚴禁的計費系統。
支付:國際化支持,多種銀行卡信用卡接入,多種貨幣支持。
NewSQL:引入TiDB等新SQL技術到某些業務,替換Redis、MongoDB、MySQL,更方便友好地進行技術開發。
直播面臨的核心問題是網站穩定可用、視頻流暢清晰、彈幕互動效果穩定。直播技術看似簡單,一家視頻云可以幫助創業公司一兩個月就構建出一個直播App,但其中的運營難點、技術難點、流量帶寬問題都需要謹慎處理,希望本文能幫助直播行業技術人員跳過一些坑,架構設計時作為技術參考。