2020年春節的這場疫情讓線下零售降至冰點,但是卻帶火了直播應用。直播電商、直播教育等各類直播應用可謂贏得了歷史性的機會,很多大眾開始接受並認可這種新型應用的便利和價值,個人感覺隨著5G的普及,『直播+垂直領域+精細化的私域流量』將會是互聯網的一個大熱點,迎來真正的紅利期。 直播行業大概在10年多前 ...
2020年春節的這場疫情讓線下零售降至冰點,但是卻帶火了直播應用。直播電商、直播教育等各類直播應用可謂贏得了歷史性的機會,很多大眾開始接受並認可這種新型應用的便利和價值,個人感覺隨著5G的普及,『直播+垂直領域+精細化的私域流量』將會是互聯網的一個大熱點,迎來真正的紅利期。
直播行業大概在10年多前就開始興起了,秀場直播和游戲直播是PC時代比較成功的應用場景,直到16年,隨著移動互聯網的大規模普及,直播行業迎來了真正的元年,成百上千的直播APP出現在大眾視野,大概在18年年初,直播答題當時火了一把,那算是直播類應用的第一次全民普及,然後是19年短視頻網站掀起的直播電商。回顧直播行業的發展歷程,直播類應用在各個領域遍地開花,那麼它背後的技術架構你是否瞭解?
兩年前,我參與了一個支持100萬用戶同時線上、20萬併發的直播答題系統的架構設計,下文將以『直播答題』的應用場景為例,帶你瞭解當前疫情下火爆的直播應用背後的技術架構。內容分成以下4個部分:
1、產品功能簡介
2、面臨的技術挑戰
3、技術選型及依據
4、架構設計方案
01 產品功能簡介
直播答題能在當時成為風口,得益於它的玩法足夠簡單,用戶教育成本幾乎為0。簡單來說就是:全民線上PK、10秒答題、超時或答錯即退出游戲、成功答對所有題即可平分獎金,俗稱線上版的開心辭典。
在瞭解系統設計方案和架構之前,先看看直播答題應用有哪些核心功能?下麵是APP端的幾張產品截圖:
1、答題以活動的形式展開,每場活動都會預先公佈直播開始時間、答題總獎金、紅包雨獎金等信息。
2、活動時間到後,用戶就可以進入直播間,看到實時的視頻流,有專業的主持人進行串詞口播,場控人員會配合主持人同步進行發題、公佈答案等操作。
3、題目下發後,用戶有10秒的作答時間,答錯或者超時即退出游戲,如果用戶有複活道具在答錯時會自動使用,用戶能繼續進行答題。
4、為了留住答錯用戶,活動期間有多場紅包雨,用戶點擊屏幕就有概率搶到。
5、活動期間用戶可發彈幕,同時會有彈幕滾屏輪播,以營造熱鬧的直播氛圍。
6、其他功能:邀請新人、活動榜單、獎金提現等。
其他直播類應用在產品功能上和直播答題類似,基本也是這兩類:
1、直播的基礎功能:連麥互動直播(支持多碼率、多協議,多主播同框)、美顏特效、彈幕、IM聊天、點贊、屏幕共用等功能性需求,以及防盜鏈、涉黃涉政鑒別等非功能性需求。
2、應用本身的個性化功能:比如答題場景中的發題目、作答、公佈答案,電商場景中的商品展示、一鍵下單購買,網紅直播場景中的禮物打賞。
02 面臨的技術挑戰
當時我們做直播答題應用時,面臨以下技術挑戰:
1、音視頻處理及傳輸:涉及音視頻編碼、實時美顏、視頻推流、CDN加速分發、終端適配和播放,流量統計等諸多技術點,而且我們當時的技術團隊沒有專門做音視頻方面的專家。
2、高併發請求:參考了沖頂大會等答題競品的用戶量級,預計會有100W用戶同時線上,1秒內有20W用戶同時答題;1秒內單個用戶可觸屏發起4-5次搶紅包請求,併發最大可達到500W QPS.
3、高帶寬壓力:按照標清視頻的標準,觀看直播的碼流至少為1Mbps,如果100W用戶線上,光視頻流的出口帶寬能達到976.56G bps。1條彈幕可達到130位元組,1秒要滾屏20條彈幕,如果需要同時推送給100W用戶,彈幕的出口帶寬也將達到19.37G bps.
4、高計算壓力:1道題目的對錯判斷涉及到答案比對、複活道具的使用、判斷用戶是否創了新紀錄,同時還涉及一系列的反作弊策略(比如前面的題目答錯了將無法繼續作答),在主持人口播公佈答案的瞬間,如何快速完成100W用戶的答題結果計算?
5、資金流的正確性和安全性:單個用戶最多搶3個紅包如何不多領?財務上如何保證答題獎金、紅包獎勵不出現1分錢的誤差?
6、低延遲性要求:直播場景下如何整合視頻流和業務數據流,做到聲音、主播畫面和題目同步,以保證用戶體驗?
7、對商城交易業務的低干擾:直播答題僅作為商城的一個運營活動,核心目標是導流,它依托商城原有的用戶體系,運營系統,大數據系統,提現通道等,如何做到對商城現有交易系統的低干擾?
可見答題這種泛娛樂的直播場景還是有挺多技術挑戰的,它取決於直播應用的用戶量級和業務流程。就算是直播電商這種低頻交易轉化的場景,要是李佳琪在帶貨,同樣也會面臨瞬時搶購的高併發挑戰,所以架構設計時必須考慮業務最高峰時的壓力,並且系統的各個環節必須具備動態可伸縮的能力。
03 技術選型及依據
一. 音視頻處理及傳輸的方案選型
音視頻處理及傳輸,因為技術團隊不具備這方面的能力,所以當時調研了各種雲廠商的付費解決方案,最終採用了騰訊雲的直播解決方案。主持人側:通過演播室的專業攝像設備,搭載騰訊雲提供的obs推流軟體,即可進行視頻錄製和推流。用戶側:APP端集成騰訊雲的SDK,動態拿到推流地址後即可觀看直播。
二. 業務數據流的方案選型
業務數據是指除音視頻以外的,和答題應用場景相關的數據(比如題目、答案、彈幕、紅包等)。騰訊雲提供了兩種可選方案:
1、題目預先設置好,直接由騰訊雲的SDK通過音視頻通道下發,打入直播流中。
2、讓題目先通過騰訊雲的IM通道快速送達觀眾端APP,在觀眾端先緩存下來,等待播放器通知了預期的 NTP 時間戳之後,再把題目顯示出來。
騰訊雲的這兩種方案都可以提供“音-畫-題”的完美同步,但是存在以下局限:用戶的答案必須以HTTP請求方式彙總到答題伺服器,這一塊必須自己開發,另外公佈答案、搶紅包、彈幕這些業務騰訊雲系統都是不支持的,在底層通信通道上仍然需要自行開發。
考慮上述局限以及業務的多變性,我們最終打算自研業務數據流通道。這樣視頻流和業務數據流會分兩個通道下發,因為業務流相對視頻流的數據量很小,只要能保證業務邏輯的處理速度和業務數據的下行速度,“音-畫-題”的延遲是可以接受的。畢竟當時已經是4G時代,如果用戶側的網速不行,視頻流可能都無法正常觀看了。
為了做到業務數據流的獨立傳輸,需要實現一個長連接、高性能的網關伺服器(支持100W用戶同時線上,20W併發答題,彈幕實時推送等要求),我們的技術選型是:Netty、ProtoBuf、WebSocket,選型理由:
1、Netty:Netty是當時最流行的高性能和非同步NIO框架,直播答題的業務場景中,涉及到題目下發、彈幕、下紅包雨等非常多的推送場景,而且一場答題活動中,客戶端和服務端的通信頻繁,長連接比短連接在性能上更優。
2、ProtoBuf:作為客戶端和服務端的數據交換格式,PB是一種效率和相容性都很優秀的二進位數據傳輸格式,在碼流和序列化速度上明顯優於JSON、XML、hessian等主流格式,同時支持向前向後相容以及各種主流語言。
3、WebSocket:是 HTML5 一種新的協議,用來實現客戶端與伺服器端的長連接通訊。
三. 服務端的部署方案選型
前面提過,直播答題僅作為商城的一個運營活動,它依托商城原有的用戶體系,運營系統,大數據系統,提現通道等。現有的商城系統部署在我們自建的機房中,為了降低對商城現有交易系統的低干擾,我們採用了『私有雲+公有雲』的混合部署方案。將高併發的答題系統以及它所依賴的緩存、MQ等公共組件部署在公有雲上,方便彈性擴展,同時降低對商城交易系統的流量衝擊。
04 架構設計方案
一. 音視頻直播架構
上面是騰訊雲直播解決方案的架構圖,其他雲廠商的直播解決方案,技術架構類似。感興趣的同學可以直接去騰訊雲官網上詳細瞭解,這裡不做展開。
二. 數據流方案
音視頻流採用了騰訊雲的直播解決方案,而業務數據流(活動、題目、答案、彈幕、紅包等)則採用了自研的長連接方案。架構圖中的答題系統和答題運營後臺也均為自研。客戶端會分開處理兩個通道的數據,以控制用戶交互上的變化。
三. 基於TCP長連接的通信架構
上面的通信架構用於業務數據流的傳輸,流程如下:
1、客戶端使用websocket與服務端進行通訊,用戶進入答題直播間時建立連接,退出直播間時斷開連接。
2、Nginx對websocket做負載均衡。
3、TCP網關基於netty實現,用於維持長連接和轉發業務請求,不負責具體的業務邏輯,它和下層業務系統(答題系統)通過RPC介面進行交互,主要考慮後續其他業務可以復用TCP網關層,所以將業務下沉。客戶端和網關之間通過心跳機制保證連接的有效性以及檢測僵屍連接。
4、消息推送(比如彈幕、下發題目、公佈答案等諸多場景)由下層業務(答題系統)通過MQ通知TCP網關,再由TCP網關推送給客戶端。
四. 長連接通信中的數據傳輸格式定義
通信架構中另外比較重要的是數據傳輸格式的定義,客戶端和TCP網關之間,TCP網關和答題系統之間均採用的是protobuf格式。下麵分開說一下比較關鍵的幾個格式定義。
4.1 客戶端請求消息的格式
1、消息類型標識:-1表示心跳消息、0表示用戶驗證消息、>0 表示業務類消息
2、用戶ID:用戶的唯一標識,在前置的登錄流程中已經獲得
3、Token:用戶登錄APP後的授權令牌,在前置的登錄流程中已經獲得
4、BizData:真正的業務數據,protobuf序列化後的byte數組,由下層業務自行定義更具體的格式
4.2 客戶端響應消息的格式
1、消息類型標識:和請求中的消息類型保持一致
2、狀態碼:0表示處理失敗,1表示處理成功
3、BizData:真正的業務數據,如果狀態碼為0,該欄位為4位元組的異常碼(100表示token驗證失敗,101表示請求業務層失敗),如果狀態碼為1,該欄位為業務層返回的protobuf序列化後的byte數組,同樣由下層業務自行定義更具體的格式
4.3 業務數據的ProtoBuf格式定義
message Message
{
MessageType messageType = 1; // 消息類型,枚舉值
string sequence = 2; // 消息序號
Request request = 3; // 請求類消息
Response response = 4; // 響應類消息
Notification notification = 5; // 推送類消息
}
這裡的格式設計比較巧妙,通過Message頂層消息把Request、Response、Notification這3類消息包裝起來,並且定義一個MessageType枚舉值,用來表示消息類型,另外sequence欄位表示消息的唯一序列號,需要保證發送端內唯一,這樣發送端收到Response後可以進行匹配處理。有了上面的統一消息格式,答題系統就可以針對不同的MessageType定義不同的消息處理器,配置好映射關係後,即可實現消息路由。
五. 系統總體架構
1、網關層:架構上同時採用了TCP網關和HTTP網關,TCP網關上一章節已經講解,它主要用於維持百萬用戶同時線上,以及答題期間的實時數據交互(包括加入直播間、推送題目、答題、推送答案、搶紅包、彈幕推送等)。HTTP網關為APP端提供Restful介面,用於低頻的數據請求,比如活動首頁、排行榜、個人獎金明細、新人邀請、分享等場景。
2、答題系統:Dubbo實現,最核心的業務服務,同時面向C端和B端系統提供RPC介面,包括活動管理、題庫管理、直播間管理、以及面向C端的高併發介面(比如加入直播間、答題、搶紅包等)。這個集群用到了很多高併發設計的通用方法:比如服務的橫向擴容能力、多級緩存、非同步化、限流等,後面的章節再做具體介紹。另外,通過MQ的事務消息+對賬機制保證資金流在答題系統和餘額系統的一致性。
3、答題運營系統:後臺系統,供運營人員和直播時的場控人員使用,可以管理活動和題目,以及直播過程中的各種業務操作(比如配合主持人的口播下發題目、公佈答案、發紅包等)。
六. 部署架構
直播答題的線上用戶量以及併發量遠超過商城的交易系統,為了減少對主交易流程的影響,採用了上述『私有雲+公有雲』的混合部署方案,自建機房和雲機房之間通過網路專線打通。直播答題有關的應用伺服器、存儲伺服器、網路帶寬都在雲端,可以根據流量監控做到快速擴容,隨著運營計劃的調整,也可以隨時增減伺服器,靈活性高。
七. 答題系統的高併發設計方案
7.1 答題介面的高併發設計方案
答題介面的併發預計20W QPS,在說設計方案之前,先簡單列一下答題介面的判斷邏輯:
1、需要判斷答題活動是否仍在進行中
2、需要判斷用戶是否已經答錯出局
3、需要判斷用戶輸入的題目是否是當前正在作答的題目
4、需要判斷用戶上一道答對的題和當前這題是否連續
5、需要判斷用戶作答是否已經超時
6、需要判斷用戶的答案是否是正確答案
7、如果答錯了,需要判斷用戶是否有複活卡
8、如果有複活卡,需要判斷前面的題是否用過複活卡了
除了上述判斷邏輯外,還有一些寫操作,比如更新每個答案選項的選擇人數,更新用戶的答對題號或者出局題號,更新複活卡的使用記錄等,總的來說,答題是一個讀多寫少的介面。為了應對高併發,我們採取了以下技術方案:
1、答題介面的所有邏輯只操作緩存,不操作資料庫。採用Write Behind Caching的更新模式(即只更新緩存,在答題結束後再非同步批量更新資料庫)。
2、多級緩存:本地緩存+Redis緩存。同時在答題活動開始之前,會先將活動的配置信息,題目,答案等所有靜態數據都預熱到本地緩存中。
3、Redis 一主多從 + 哨兵的部署架構,確保高併發和高可用,同時分業務模塊配置了多套Redis實例(用戶、彈幕、直播作答、獎金榜單)做進一步分流。
4、調整判斷邏輯的順序,上面提到的8個判斷邏輯,其中前4個都屬於安全校驗,因為客戶端已經通過交互做了攔截,如果用戶不採取作弊手段肯定都能校驗通過。所以我們將第5、6、7步邏輯做了前置,通過後再進行前4步校驗,這樣大大減少了計算量。
7.2 答題結果推送的設計方案
如何在主持人口播公佈答案的瞬間,將答題結果推送給幾十萬作答用戶?因為用戶的作答結果有非常多的狀態:有答對的和答錯的,有使用複活卡和未使用複活卡的,有出局的,不同狀態下APP端的交互均不同,完全是一種依賴服務端的有狀態推送。為瞭解決這個併發計算問題,我們採用了一個比較巧的設計方案,很好地將有狀態推送轉變成了無狀態推送:
1、將答題結果的計算前置到用戶提交答案的時候同步完成(上一節的方案),這樣相當於將瞬時的計算壓力分散到10秒作答時間里了。
2、用戶的作答結果也在第1步計算完成後立刻推送給用戶了,不用等到主持人口播公佈答案的瞬間,否則的話仍然涉及到併發讀取作答結果以及有狀態推送,對存儲伺服器以及帶寬的瞬時壓力仍然存在。
3、但是作答結果如果提前推送給客戶端必然存在安全問題,黑客抓包就能提前知道是否答對了,可以利用批量賬號進行作弊。為瞭解決這個問題,我們對作答結果採用XOR進行了對稱加密,同時將秘鑰延遲到公佈答案的瞬間才下發,而且每道題的秘鑰均是隨機生成的。這樣就很好地解決了安全問題。
4、公佈答案的瞬間,我們只需要推送一個非常小的數據包給客戶端即可,而且這個數據包所有用戶都是一樣的。
7.3 搶紅包介面的高併發設計方案
屏幕下紅包雨,用戶觸屏點中紅包就直接拆了,所以搶紅包介面的併發非常高,1秒內單個用戶可觸屏發起4-5次搶紅包請求,按照百萬用戶線上,併發最大可達到上百萬QPS,下麵說下技術方案:
1、紅包金額提前計算好並載入到redis中:在創建活動時,運營可配置紅包總金額以及紅包總個數,系統在創建活動時就會提前計算出各個紅包的金額並存儲到redis中,相當於計算前置。
2、客戶端限流:在介面設計時,我們就預埋了一個限流因數參數,可由服務端動態控制客戶端的限流比例,在通知客戶端搶紅包的介面中,我們根據當前的線上人數以及紅包總個數動態算出限流因數,控制最多只有10W QPS的請求能發到服務端。
3、服務端限流:根據伺服器數量以及紅包總數量提前計算出每秒令牌的生成數量,基於guava的RateLimiter進行二次限流。
4、前面3步基本把併發降下來了,再通過lua腳本保證原子性即可,搶紅包的結果也是在活動結束後再非同步刷新到資料庫。
7.4 其他高併發的優化點
1、Redis緩存的對象要儘可能簡化(用不到的欄位不要存),key的長度要儘可能短(高併發下的瓶頸在於IO),善於利用pipeline組裝多個命令(但是命令個數不能過多)
2、各種連接池和JVM參數的調整:涉及redis連接池、dubbo的線程池、JVM記憶體大小,可以在壓測環境下找到合理值。
3、答題系統可水平擴展(scale out),同時通過dubbo的分組配置將ToB和ToC介面進行隔離部署,避免相互影響。
最後,關於直播架構再簡單總結下:
1、音視頻編碼和傳輸,這些基礎性的直播功能,除非公司有錢有實力,否則建議直接用騰訊雲或者其他雲廠商的解決方案(鬥魚、蘑菇街這些知名的直播應用都還用的騰訊雲)。
2、架構設計重點放在應用本身,根據直播應用的用戶量級和業務特性先確定通信架構(長連接還是短鏈接,或者兩者混用)。
3、要根據業務高峰來做方案設計,如果是高併發場景,要把高併發當做一個系統性問題去對待:從客戶端到服務端,從網路帶寬到部署架構,甚至產品設計等各個維度全盤考慮,要摳各種細節。
作者簡介:程式員,985碩士,前亞馬遜Java工程師,現58轉轉技術總監。持續分享技術和管理方向的文章。如果感興趣,可微信掃描下麵的二維碼關註我的公眾號:『IT人的職場進階』