本文由融云技術團隊原創分享,原題“技術實踐丨萬人群聊的消息分發控速方案”,為使文章更好理解,內容有修訂。
1、引言
傳統意義上的IM群聊,通常都是像微信這樣的500人群,或者QQ的2000人群(QQ有3000人群,但那是單獨收費的,也就意味著它并非無門檻標配,能用上的人并不多)。
自從國外某號稱“世界上最安全的IM”搞出萬人群聊之后,萬人群迅速被國內的使用者們接受。伴隨著移動互聯網的發展,即時通訊服務被廣泛應用于各個行業(以經不再局限于傳統IM社交應用領域),隨著業務快速發展,傳統百人、千人上限的群聊已經無法滿足很多業務場景需求,所以萬人甚至十萬人的超大群也算是相伴而生、順應潮流。
▲ “紙飛機”的萬人群(開發人員顫抖中...)
IM群聊一直是IM應用中比較有難度的熱點技術之一,通常意義的群聊,無非就是500人群、1000人群、2000人群這樣,技術實現上比單聊要復雜不少。然而對于萬人群聊(甚至十萬人群聊)來說,相比百人、千人群聊,技術實現上那幾乎是另一個技術維度的事情,難度要高很多。
本文根據融云技術團隊的實踐經驗,總結了萬人群聊消息投遞方案的一些思考和實踐,希望能給你帶來啟發。
學習交流:
(本文同步發布于:http://www.52im.net/thread-3687-1-1.html)
2、相關文章
萬人群聊有關的技術文章還可讀一讀以下這篇:
- 《網易云信技術分享:IM中的萬人群聊技術方案實踐總結》
- 《企業微信的IM架構設計揭秘:消息模型、萬人群、已讀回執、消息撤回等》
- 《阿里釘釘技術分享:企業級IM王者——釘釘在后端架構上的過人之處》
融云技術團隊分享的其它文章:
- 《融云技術分享:融云安卓端IM產品的網絡鏈路保活技術實踐》
- 《融云技術分享:全面揭秘億級IM消息的可靠投遞機制》
- 《融云技術分享:基于WebRTC的實時音視頻首幀顯示時間優化實踐》
- 《IM消息ID技術專題(三):解密融云IM產品的聊天消息ID生成策略》
3、超大群面臨的技術挑戰
與百人群、千人群相比,萬人、甚至十萬人超大群,大幅提升了群的觸達人數,對于很多業務場景來說,好處不言而喻。
然而單群成員如此之大,給 IM 系統的流量沖擊非常巨大,技術難度可想而之。我們先來分析一下超大群的技術挑戰。
以一個萬人群的模型為例:
- 1)如果群中有人發了消息,那么這條消息需要按照 1:9999 的比例進行分發投遞,如果我們按照常規消息的處理流程,那么消息處理服務壓力巨大;
- 2)消息量大的情況下,服務端向客戶端直推消息的處理速度將會成為系統瓶頸,而一旦用戶的消息下發隊列造成了擠壓,會影響到正常的消息分發,也會導致服務緩存使用量激增;
- 3)在微服務架構中,服務以及存儲(DB,緩存)之間的 QPS 和網絡流量也會急劇增高;
- 4)以群為單位的消息緩存,內存和存儲開銷較大(消息體的存儲被放大了萬倍)。
基于這些技術挑戰,要想真正達成超大群的技術目標,勢必要做特定的技術優化來應對。
4、一般群聊的消息投遞模型
先來看看普通群聊的消息投遞模型。
我們的普通群聊消息投遞模型如下圖所示:
如上圖所示,當用戶在普通群里發了一條消息后,投遞路徑是:
- 1)消息先到群組服務;
- 2)然后通過群組服務緩存的群關系,鎖定這條消息最終需要分發的目標用戶;
- 3)再根據一定的策略分發到消息服務上;
- 4)消息服務再根據用戶的在線狀態和消息狀態來判斷這條消息是直推、通知拉取還是轉 Push,最終投遞給目標用戶。
普通群聊的消息投遞,正像您期待的那樣,基本上大家的實現手段都大差不差。然而對于萬人群來說,這顯然還不夠。
下面來看看我們針對萬人群聊消息投遞的技術優化手段。
5、萬人群聊消息投遞優化手段1:控速
針對萬人群的消息投遞,我們的一個主要手段就是控速。
如上圖所示。
首先:我們會根據服務器的核數來建立多個群消息分發隊列,這些隊列我們設置了不同的休眠時間以及不同的消費線程數。
通俗來講,可以將隊列這樣劃分為快、中、慢等隊列。
其次:我們根據群成員數量的大小來將所有群映射到相應的隊列中。
規則是:
- 1)小群映射到快隊列中;
- 2)大群映射到相應的慢隊列中。
然后:小群由于人數少,對服務的影響很小,所以服務利用快隊列快速的將群消息分發出去,而大群群消息則利用慢隊列的相對高延時來起到控速的作用。
6、萬人群聊消息投遞優化手段2:合并
在本文第3節中提到的萬人群聊所面臨的技術挑戰,最主要的挑戰其實就是消息進行擴散分發投遞后,消息被克隆出N條,消息流量瞬間被放大。
舉個例子:當一條群消息發送到 IM 服務器后,需要從群組服務投遞給消息服務,如果每一個群成員都投遞一次,并且投遞的群消息內容是一致的話,那肯定會造成相應的資源浪費和服務壓力。
那么針對這種情況,我們的解決方案就是進行消息合并投遞。
原理就是:服務落點計算中我們使用的是一致性哈希,群成員落點相對固定,所以落點一致的群成員我們可以合并成一次請求進行投遞,這樣就大幅提高了投遞效率同時減少了服務的壓力。
下圖是云信團隊分享的萬人群消息合并投遞邏輯:
▲ 上圖引用自《IM中的萬人群聊技術方案實踐總結》
如上圖所示,云信團隊的萬人群消息合并投遞方案是:按Link分組路由消息,同一Link上的全部群成員只需要路由一條消息即可。
7、十萬、百萬級的超大群處理方案
在實際群聊業務中,還有一種業務場景是超大規模群,這種群的群人數達到了數十萬甚至上百萬。
這種群如果按照上述的投投遞方案,勢必仍會造成消息節點的巨大壓力。
比如我們有一個十萬人的群,消息節點五臺,消息服務處理消息的上限是一秒鐘 4000 條,那每臺消息節點大約會分到 2 萬條群消息,這已大大超出了消息節點的處理能力。
所以為了避免上述問題,我們會將群成員上線超過3000的群識別為萬人群、超級群,這種級別的群可以根據服務器數量和服務器配置相應做調整針對這種超級群會用特殊的隊列來處理群消息的投遞。
這個特殊的隊列1秒鐘往后端消息服務投遞的消息數是消息服務處理上限的一半(留相應的能力處理其他消息),如果單臺消息服務處理的 QPS 上限是 4000,那群組服務一秒往單臺消息服務最多投遞 2000 條。
8、寫在最后
未來,我們也會針對群消息進行引用投遞,對于大群里發的消息體比較大的消息,我們給群成員只分發和緩存消息的索引,比如 MessageID。等群成員真正拉取群消息時再從將消息組裝好給客戶端分發下去。這樣做會節省分發的流量以及存儲的空間。
隨著互聯網的發展,群組業務的模型和壓力也在不停地擴展,后續可能還會遇到更多的挑戰,當然也會不斷迭代出更優的處理方式來應對。
附錄:更多IM群聊技術文章
《快速裂變:見證微信強大后臺架構從0到1的演進歷程(一)》
《如何保證IM實時消息的“時序性”與“一致性”?》
《IM單聊和群聊中的在線狀態同步應該用“推”還是“拉”?》
《IM群聊消息如此復雜,如何保證不丟不重?》
《微信后臺團隊:微信后臺異步消息隊列的優化升級實踐分享》
《移動端IM中大規模群消息的推送如何保證效率、實時性?》
《現代IM系統中聊天消息的同步和存儲方案探討》
《關于IM即時通訊群聊消息的亂序問題討論》
《IM群聊消息的已讀回執功能該怎么實現?》
《IM群聊消息究竟是存1份(即擴散讀)還是存多份(即擴散寫)?》
《一套高可用、易伸縮、高并發的IM群聊、單聊架構方案設計實踐》
《[技術腦洞] 如果把14億中國人拉到一個微信群里技術上能實現嗎?》
《IM群聊機制,除了循環去發消息還有什么方式?如何優化?》
《網易云信技術分享:IM中的萬人群聊技術方案實踐總結》
《阿里釘釘技術分享:企業級IM王者——釘釘在后端架構上的過人之處》
《IM群聊消息的已讀未讀功能在存儲空間方面的實現思路探討》
《直播系統聊天技術(一):百萬在線的美拍直播彈幕系統的實時推送技術實踐之路》
《直播系統聊天技術(二):阿里電商IM消息平臺,在群聊、直播場景下的技術實踐》
《直播系統聊天技術(三):微信直播聊天室單房間1500萬在線的消息架構演進之路》
《直播系統聊天技術(四):百度直播的海量用戶實時消息系統架構演進實踐》
《企業微信的IM架構設計揭秘:消息模型、萬人群、已讀回執、消息撤回等》
《融云IM技術分享:萬人群聊消息投遞方案的思考和實踐》
>> 更多同類文章 ……
本文已同步發布于“即時通訊技術圈”公眾號。
同步發布鏈接是:http://www.52im.net/thread-3687-1-1.html