分布式彈幕服務架構

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

今天簡單記錄一下彈幕伺服器的設計思路,希望對大家有所協助。

業務特點

彈幕典型的進少出多情境,一個房間如果有10W觀眾,每秒提交的彈幕也許只有1000次,但是廣播彈幕給所有觀眾需要1000 * 10W次。

單機模型

為了推送訊息,長串連幾乎是必然的選擇。

每個房間有若干觀眾,所有房間的觀眾都串連在1個服務進程上。

當彈幕提交上來,根據房間找出所有房間內的線上使用者,迴圈將彈幕推送給他們。

假設1個服務進程的訊息網路吞吐能力是50萬次/秒,那麼一個10萬觀眾的房間,每秒提交5次彈幕就會達到服務端極限效能。

多機模型

假設一個直播間仍舊有10萬人線上,希望解決每秒5次彈幕就達到效能瓶頸的問題,很容易想到能否橫向擴充解決。

假設現在有2台伺服器,10萬人均勻串連在2台伺服器上,也就是一台有5萬人線上。

現在任意使用者發送1條彈幕到A伺服器,那麼A伺服器推送5萬次,並且將彈幕轉寄給B伺服器,B伺服器也只需要推送5萬次。

假設要達到A,B伺服器的極限,只需要每秒有10條彈幕即可。。。那麼橫向擴充的收益就這麼小嗎?

顯然有更不為人知的秘密存在。

批量模型

實際上,如果每個彈幕推送都作為一個獨立的tcp包發送,那麼網卡將很快達到瓶頸,因為幾乎每個包都要經過一次核心中斷交付給網卡,從而送出到網路中,這對網卡是不友好的。

根據實測經驗,萬兆網卡的每秒發包量大約在100-200萬之間,之前我舉例說50萬次/秒實際說的比實際情況少一些。

如果可以減少網路發包的次數,那麼就可以解決網卡的瓶頸,從而突破每秒廣播50萬人次彈幕的瓶頸。

思路就是批量,可以將原本要立即發送給觀眾的彈幕緩衝起來,每間隔1秒將這些緩衝的彈幕作為一個整體,發送給各個觀眾的tcp串連。

在這樣的實現下,無論每秒是50條彈幕還是10000條彈幕提交到服務端,每秒的推送網路調用次數都是10萬人次,也就是按秒為單位彙總彈幕,這樣網路調用次數只與線上觀眾數相關了。

依舊是之前的伺服器效能(極限每秒50萬次網路調用),那麼可以支撐50萬觀眾同時線上,每秒將1秒內緩衝的彈幕作為整體發送給50萬觀眾,也就是這一秒只有50萬次的網路調用,在網卡的承受範圍之內。

在網路這一塊來說,通過增加單次發送包的大小可以減少發包數量,提升頻寬利用率,每秒送達的彈幕數量並沒有受到影響(雖然每秒能夠發出的包個數少了,但是單個包內有很多彈幕,總體保持不變),即延遲換吞吐。

接下來呢

從bilibili的彈幕服務壓測資料來看,單個伺服器單機每秒下發3500萬+彈幕,承載大約100萬的線上觀眾,單次發送打包的彈幕數量大約是3500萬/100萬=35條的樣子,也就是每秒35條彈幕提交到服務端,然後打包廣播給所有觀眾,頻寬成為了瓶頸。

在觀眾數量不變的情況下,即便每秒提交10000條彈幕,那麼瓶頸也只在頻寬(推送的打包變大了)和CPU(彙總訊息),只要觀眾數量變成80萬,那麼頻寬又將有更多的冗餘,CPU也會相應降低。

整個彈幕系統的瓶頸再也並不是每秒的彈幕數量了,而是觀眾數量決定:

每秒網路發送的次數=觀眾數量!=彈幕數量

這是很重要的結論!通過增加伺服器均分觀眾,那麼每台伺服器每秒的推送次數就可以減少,只要叢集有足夠大的出口頻寬,那麼一切都不是問題!

架構

設計系統都講究無狀態,這樣做複雜度最低。

其實彈幕本質算是IM系統,IM系統一般支援1對1,1:N的聊天方式。

IM系統在擴充性方面有一些慣例,下面基於bilibili的彈幕架構簡單說說原理。

comet是網關,無狀態,負責用戶端長串連和訊息收發。

logic是邏輯伺服器,無狀態,做商務邏輯用,保持comet邏輯單一高效能。

router有狀態(記憶體狀態),logic通過使用者uid一致性雜湊儲存使用者的會話資訊在某個router。

一個uid可以進入多個房間,建立多條串連到不同comet,而每個直播間在不同伺服器上都可能有使用者線上。

使用者向房間發彈幕直接通過HTTP協議調用logic服務,而logic直接發給kafka,由job服務消費廣播給所有Comet。

使用者也可以定向發送訊息,可能直接發給個人,發給某個房間,發給全部房間。

發訊息給個人的話logic查詢router,擷取uid在哪些server上的哪些room。然後向kafka上推送一條記錄,由job服務將訊息廣播給這些server上的room,這樣無論該使用者在N個直播間裡任意一個都可以看到推送。

發送全部房間和發送一個房間類似,就是由job廣播給所有comet,然後每個Comet給所有使用者發訊息。

效能

其實推送有個程式設計問題,就是要推送的使用者量很大,而使用者頻繁的在上線與下線,因此線上使用者集合是上鎖的。

推送就要遍曆集合,所以很矛盾。

這個問題只能通過拆分集合實現,每個集合只維護部分使用者,通過UID雜湊分區。

推送訊息時,逐個遍曆每個小集合上鎖處理。推送某個房間也是類似的,只需要遍曆每個小集合,在小集合裡找出對應房間的使用者即可。

擴充閱讀

bilibili的彈幕系統是開源的,感興趣可以詳細分析他的代碼,用的是golang標準庫的rpc,額外依賴了kafka,整體設計還是不算複雜的。

github:https://github.com/Terry-Mao/goim/

部落格:http://geek.csdn.net/news/detail/96232

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.