本文由融雲技術團隊原創分享,原題“聊天室海量訊息分發之訊息丟棄策略”,內容有修訂。
1、引言
隨著直播類應用的普及,尤其直播帶貨概念的風靡,大使用者量的直播間場景已然常態化。
大使用者量直播間中的實時互動是非常頻繁的,具體體現在技術上就是各種使用者聊天、彈幕、禮物、點贊、禁言、系統通知等實時訊息。
如此大量的實時訊息,在分發時如何處理才能不至於把服務端搞垮,而到了客戶端時也不至於讓APP出現瘋狂刷屏和卡頓(不至於影響使用者體驗),這顯然需要特殊的技術手段和實現策略才能應對。
其實,直播間中的實時訊息分發,在技術上是跟傳統的線上聊天室這種概念是一樣的,只是傳統網際網路時代,聊天室同時線上的使用者量不會這麼大而已,雖然量級不同,但技術模型是完全可以套用的。
本文將基於直播技術實踐的背景,分享了單直播間百萬使用者線上量的實時訊息分發的技術經驗總結,希望帶給你啟發。
學習交流:
- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
- 開源IM框架原始碼:https://github.com/JackJiang2...
(本文已同步釋出於:http://www.52im.net/thread-37...)
2、系列文章
本文是系列文章中的第6篇:
《直播系統聊天技術(一):百萬線上的美拍直播彈幕系統的實時推送技術實踐之路》
《直播系統聊天技術(二):阿里電商IM訊息平臺,在群聊、直播場景下的技術實踐》
《直播系統聊天技術(三):微信直播聊天室單房間1500萬線上的訊息架構演進之路》
《直播系統聊天技術(四):百度直播的海量使用者實時訊息系統架構演進實踐》
《直播系統聊天技術(五):微信小遊戲直播在Android端的跨程式渲染推流實踐》
《直播系統聊天技術(六):百萬人線上的直播間實時聊天訊息分發技術實踐》(* 本文)
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、寫在最後
隨著移動網際網路的發展,直播間的實時訊息業務模型和壓力也在不停地擴充套件變化,後續可能還會遇到更多的挑戰,我們的服務會與時俱進、跟進更優的方案策略進行應對。
附錄:多人群聊天技術文章
[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技術分享:萬人群聊訊息投遞方案的思考和實踐》
(本文已同步釋出於:http://www.52im.net/thread-37...)