百萬人在線的直播間實時聊天消息分發技術實踐

本文由融雲技術團隊原創分享,原題“聊天室海量消息分發之消息丟棄策略”,內容有修訂。

1、引言

隨着直播類應用的普及,尤其直播帶貨概念的風靡,大用戶量的直播間場景已然常態化。

大用戶量直播間中的實時互動是非常頻繁的,具體體現在技術上就是各種用戶聊天、彈幕、禮物、點贊、禁言、系統通知等實時消息。

如此大量的實時消息,在分發時如何處理才能不至於把服務端搞垮,而到了客戶端時也不至於讓APP出現瘋狂刷屏和卡頓(不至於影響用戶體驗),這顯然需要特殊的技術手段和實現策略才能應對。

其實,直播間中的實時消息分發,在技術上是跟傳統的在線聊天室這種概念是一樣的,只是傳統互聯網時代,聊天室同時在線的用戶量不會這麼大而已,雖然量級不同,但技術模型是完全可以套用的。

本文將基於直播技術實踐的背景,分享了單直播間百萬用戶在線量的實時消息分發的技術經驗總結,希望帶給你啓發。

2、系列文章

本文是系列文章中的第6篇:

3、技術挑戰

我們以一個百萬人觀看的直播間爲例進行分析,看看需要面臨哪些技術挑戰。

1)在直播中會有一波一波的消息高峯,比如直播中的“刷屏”消息,即大量用戶在同一時段發送的海量實時消息,一般情況下此類“刷屏”消息的消息內容基本相同。如果將所有消息全部展示在客戶端,則客戶端很可能出現卡頓、消息延遲等問題,嚴重影響用戶體驗。

2)海量消息的情況下,如果服務端每條消息都長期存儲將導致服務緩存使用量激增,使得內存、存儲成爲性能瓶頸。

3)在另外一些場景下,比如直播間的房間管理員進行操作後的通知消息或者系統通知,一般情況下這類消息是較爲重要的,如何優先保障它的到達率。

基於這些挑戰,我們的服務需要做一個基於業務場景的優化來應對。

4、架構模型

我們的架構模型圖如下:

 

如上圖所示,下面將針對主要服務進行簡要說明。

1)直播間服務:

主要作用是:緩存直播間的基本信息。包括用戶列表、禁言/封禁關係、白名單用戶等。

2)消息服務:

主要作用是:緩存本節點需要處理的用戶關係信息、消息隊列信息等。

具體說是以下兩個主要事情。

直播間用戶關係同步:

  • a)成員主動加入退出時:直播間服務同步至==> 消息服務;
  • b)分發消息發現用戶已離線時:消息服務同步至==> 直播間服務。

發送消息:   

  • a)直播間服務經過必要校驗通過後將消息廣播至消息服務;
  • b)直播間服務不緩存消息內容。

3)Zk(就是 Zookeeper 啦):

主要作用就是:將各服務實例均註冊到 Zk,數據用於服務間流轉時的落點計算。

具體就是:

  • a)直播間服務:按照直播間 ID 落點;
  • b)消息服務:按照用戶 ID 落點。

4)Redis:

主要作爲二級緩存,以及服務更新(重啓)時內存數據的備份。

5、消息分發總體方案

直播間服務的消息分發完整邏輯主要包括:消息分發流程和消息拉取流程。

5.1 消息分發流程

如上圖所示,我們的消息分發流程主要是以下幾步:

  • 1)用戶 A 在直播間中發送一條消息,首先由直播間服務處理;
  • 2)直播間服務將消息同步到各消息服務節點;
  • 3)消息服務向本節點緩存的所有成員下發通知拉取;
  • 4)如上圖中的“消息服務-1”,將向用戶 B 下發通知。

另外,因爲消息量過大,我們在在分發的過程中,是具有通知合併機制的,通知合併機制主要提現在上述步驟 3 中。

上述步驟3的通知合併機制原理如下:

  • a)將所有成員加入到待通知隊列中(如已存在則更新通知消息時間);
  • b)下發線程,輪訓獲取待通知隊列;
  • c)向隊列中用戶下發通知拉取。

通過通知合併機制,我們可以可保障下發線程一輪只會向同一用戶發送一個通知拉取,即多個消息會合併爲一個通知拉取,從面有效提升了服務端性能且降低了客戶端與服務端的網絡消耗。

PS:以上通知合併機制,在大消息量的情況下,非常適合使用Actor分佈式算法來實現,有興趣的同學可以進一步學習《分佈式高併發下Actor模型如此優秀》、《分佈式計算技術之Actor計算模式》。

5.2 消息拉取流程

 

如上圖所示,我們的消息拉取流程主要是以下幾步:

  • 1)用戶 B 收到通知後將向服務端發送拉取消息請求;
  • 2)該請求將由“消息服務-1”節點處理;
  • 3)“消息服務-1”將根據客戶端傳遞的最後一條消息時間戳,從消息隊列中返回消息列表(原理詳見下圖 ▼);
  • 4)用戶 B 獲取到新的消息。

上述步驟 3 中拉取消息的具體邏輯如下圖所示:

6、消息分發的丟棄策略

對於直播間中的用戶來說,很多消息其實並沒有太多實際意義,比如大量重複的刷屏消息和動態通知等等,爲了提升用戶體驗,這類消息是可以有策略地進行丟棄的(這是跟IM中的實時聊天消息最大的不同,IM中是不允許丟消息的)。

PS:直播間中消息分發的丟棄策略,跟上節中的通知合併機制一起,使得直接間海量消息的穩定、流暢分發得以成爲可能。

我們的丟棄策略主要由以下3部分組成:

  • 1)上行限速控制(丟棄)策略;
  • 2)下行限速控制(丟棄)策略;
  • 3)重要消息防丟棄策略。

如下圖所示:

我們來逐個解釋一下。

1)上行限速控制(丟棄)策略:

針對上行的限速控制,我們默認是 200 條/秒,根據業務需要可調整。達到限速後發送的消息將在直播間服務丟棄,不再向各消息服務節點同步。

2)下行限速控制(丟棄)策略:

針對下行的限速控制,即對消息環形隊列(見“5.2 消息拉取流程”中的拉取消息詳細邏輯圖)長度的控制,達到最大值後最“老”的消息將被淘汰丟棄。

每次下發通知拉取後服務端將該用戶標記爲“拉取中”,用戶實際拉取消息後移除該標記。

拉取中標記的作用:例如產生新消息時用戶具有拉取中標記,如果距設置標記時間在 2 秒內則不會下發通知(降低客戶端壓力,丟棄通知未丟棄消息),超過 2 秒則繼續下發通知(連續多次通知未拉取則觸發用戶踢出策略,不在此贅述)。

因此消息是否被丟棄取決於客戶端拉取速度(受客戶端性能、網絡影響),客戶端及時拉取消息則沒有被丟棄的消息。

3)重要消息防丟棄策略:

如前文所述:在直播間場景下對某些消息應具有較高優先級,不應丟棄。

例如:直播間的房間管理員進行操作後的通知消息或者系統通知。

針對此場景:我們設置了消息白名單、消息優先級的概念,保障不丟棄。如本節開始的圖所示,消息環形隊列可以爲多個,與普通直播間消息分開則保障了重要消息不丟棄。

通過上述“1)上行限速控制(丟棄)策略”和“下行限速控制(丟棄)策略”保障了:

  • 1)客戶端不會因爲海量消息出現卡頓、延遲等問題;
  • 2)避免出現消息刷屏,肉眼無法查看的情況;
  • 3)同時降低了服務端存儲壓力,不會因爲海量消息出現內存瓶頸從而影響服務。

7、寫在最後

隨着移動互聯網的發展,直播間的實時消息業務模型和壓力也在不停地擴展變化,後續可能還會遇到更多的挑戰,我們的服務會與時俱進、跟進更優的方案策略進行應對。

8、參考資料

[1]《IM單聊和羣聊中的在線狀態同步應該用“推”還是“拉”?

[2]《IM羣聊消息如此複雜,如何保證不丟不重?

[3]《移動端IM中大規模羣消息的推送如何保證效率、實時性?

[4]《現代IM系統中聊天消息的同步和存儲方案探討

[5]《關於IM即時通訊羣聊消息的亂序問題討論

[6]《IM羣聊消息的已讀回執功能該怎麼實現?

[7]《IM羣聊消息究竟是存1份(即擴散讀)還是存多份(即擴散寫)?

[8]《一套高可用、易伸縮、高併發的IM羣聊、單聊架構方案設計實踐

[9]《IM羣聊機制,除了循環去發消息還有什麼方式?如何優化?

[10]《網易雲信技術分享:IM中的萬人羣聊技術方案實踐總結

[11]《阿里釘釘技術分享:企業級IM王者——釘釘在後端架構上的過人之處

[12]《IM羣聊消息的已讀未讀功能在存儲空間方面的實現思路探討

[13]《企業微信的IM架構設計揭祕:消息模型、萬人羣、已讀回執、消息撤回等

[14]《融雲IM技術分享:萬人羣聊消息投遞方案的思考和實踐

學習交流:

- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM

- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK 

本文已同步發佈於:http://www.52im.net/thread-3799-1-1.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章