<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jack Jiang

    我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
    posts - 494, comments - 13, trackbacks - 0, articles - 1

    本文由vivo互聯(lián)網(wǎng)服務器團隊Cai Linfeng分享,來自公眾號“ vivo互聯(lián)網(wǎng)技術”,原題“百萬級群聊的設計實踐”,下文進行了排版優(yōu)化和內容修訂。

    1、引言

    現(xiàn)在IM群聊產(chǎn)品多種多樣,有國民級的微信、QQ,企業(yè)級的釘釘、飛書,還有許多公司內部的IM工具,這些都是以客戶端為主要載體。而且群聊人數(shù)通常都是有限制,微信正常群人數(shù)上限是500,QQ2000人,收費能達到3000人,這里固然有產(chǎn)品考量,但技術成本、資源成本也是很大的因素。筆者的業(yè)務場景上正好需要一個迭代更新快、輕量級(不依賴客戶端)、單群百萬群成員的純H5的IM產(chǎn)品。

    本文將回顧實現(xiàn)一個支持百萬人超大群聊的Web端IM架構時遇到的技術挑戰(zhàn)和解決思路,內容包括:通信方案選型、消息存儲、消息有序性、消息可靠性、未讀數(shù)統(tǒng)計。希望能帶給你啟發(fā)。

    技術交流:

    (本文已同步發(fā)布于:http://www.52im.net/thread-4789-1-1.html)

    2、技術目標

    不同的群聊產(chǎn)品,采用的技術方案是不同的,為了理解接下來的技術選型,需要先了解下這群聊產(chǎn)品的特性。

    以下是我們的技術目標:

    • 1)單群成員需要支撐百萬人,同時在線百萬級;
    • 2)功能、體驗要接近純客戶端實現(xiàn)方案;
    • 3)用戶端完全用H5承載。

    3、Web端即時通訊技術

    即時通信常見的通信技術有短輪詢、長輪詢、Server-Sent Events(SSE)、Websocket。

    具體是:

    • 1)短輪詢和長輪詢適用于實時性要求不高的場景,比如論壇的消息提醒;
    • 2)SSE 適用于服務器向客戶端單向推送的場景,如實時新聞、股票行情;
    • 3)Websocket 適用于實時雙向通信的場景,實時性好,且服務端、前端都有比較成熟的三方包,如 socket.io,所以這塊在方案選擇中是比較 easy 的,前后端使用 Websocket 來實現(xiàn)實時通信。

    相關的資料可以進一步閱讀:

    1. 新手入門貼:史上最全Web端即時通訊技術原理詳解
    2. Web端即時通訊技術盤點:短輪詢、Comet、Websocket、SSE
    3. 網(wǎng)頁端IM通信技術快速入門:短輪詢、長輪詢、SSE、WebSocket
    4. 搞懂現(xiàn)代Web端即時通訊技術一文就夠:WebSocket、socket.io、SSE
    5. WebSocket從入門到精通,半小時就夠!

    4、群聊消息的分發(fā)模式

    群聊消息的分發(fā)方式,主流有2種方式:讀擴散、寫擴散。

    下圖展示了它們的區(qū)別,區(qū)別就在于消息是寫一次還是寫N次,以及如何讀取:

    1)讀擴散:就是所有群成員共用一個群信箱,當一個群產(chǎn)生一條消息時,只需要寫入這個群的信箱即可,所有群成員從這一個信箱里讀取群消息。

    • 優(yōu)點是:寫入邏輯簡單,存儲成本低,寫入效率高。
    • 缺點是:讀取邏輯相對復雜,要通過消息表與其他業(yè)務表數(shù)據(jù)聚合;消息定制化處理復雜,需要額外的業(yè)務表;可能還有IO熱點問題。

    舉個例子:

    很常見的場景,展示用戶對消息的已讀未讀狀態(tài),這個時候公共群信箱就無法滿足要求,必須增加消息已讀未讀表來記錄相關狀態(tài)。還有用戶對某條消息的刪除狀態(tài),用戶可以選擇刪除一條消息,但是其他人仍然可以看到它,此時也不適合在公共群信箱里拓展,也需要用到另一張關系表,總而言之針對消息做用戶特定功能時就會比寫擴散復雜。

    2)寫擴散:就是每個群成員擁有獨立的信箱,每產(chǎn)生一條消息,需要寫入所有群成員信箱,群成員各自從自己的信箱內讀取群消息。

    • 優(yōu)點是:讀取邏輯簡單,適合消息定制化處理,不存在IO熱點問題。
    • 缺點是:寫入效率低,且隨著群成員數(shù)增加,效率降低;存儲成本大。

    所以當單群成員在萬級以上時,用寫擴散就明顯不太合適了,寫入效率太低,而且可能存在很多無效寫入,不活躍的群成員也必須得有信箱,存儲成本是非常大的,因此采用讀擴散是比較合適的。

    據(jù)了解,微信是采用寫擴散模式(詳見《企業(yè)微信的IM架構設計揭秘:消息模型、萬人群、已讀回執(zhí)、消息撤回等》),微信群設定是500人上限,寫擴散的缺點影響就比較小。

    5、架構設計

    5.1 整體架構

    先來看看群聊的架構設計圖,如下圖所示:

    從用戶登錄到發(fā)送消息,再到群用戶收到這條消息的系統(tǒng)流程如下圖所示:

    解釋一下邏輯:

    1)用戶登錄,通過負載均衡,與連接服務建立 Websocket 長連接;

    2)連接服務管理會話,管理群與用戶的映射關系,在本地內存里使用哈希表存儲,key為groupId,value為List,同一個群的用戶可能會在不同的集群服務器上;

    3)連接服務向群組服務上報群組路由,上報它的內網(wǎng)IP和它所管理的 groupIdList 的關系,這里需要2種同步策略并行保證群組路由信息的準確性:a.在用戶建立、斷開長連接時即刻上報;b.定時上報;

    4)群組服務管理群組路由,使用遠程中心緩存 Redis 管理 groupId 和連接服務器IP的關系,key 為 groupId,value 為 List,該IP為連接服務的內網(wǎng)IP地址,這里會做上報的心跳判斷,超過3個心跳周期不上報,則認為已斷線;

    5)用戶在群里發(fā)布一條消息,消息通過 Websokcet 送達連接服務,然后經(jīng)過連接服務—>消息隊列—>群組服務,消息在群組服務里經(jīng)過頻控、安全檢查、格式轉換等一系列流程后入庫,持久化;

    6)群組服務通過群組路由管理獲取這條消息所屬群的路由信息,即一組連接服務的IP地址,然后通過 HTTP 回調對應的連接服務,通知它們有新消息產(chǎn)生,這里只簡單傳遞消息ID;

    7)連接服務收到 HTTP 請求后,根據(jù)會話管理查詢該群所有用戶,給用戶發(fā)送新消息提醒;

    8)用戶收到新消息提醒,通過 Websocket 來連接服務拉取該新消息具體詳情,然后根據(jù)消息協(xié)議展示在信息流里。

    5.2 路由策略

    用戶應該連接到哪一臺連接服務呢?

    這個過程重點考慮如下2個問題:

    • 1)盡量保證各個節(jié)點的連接均衡;
    • 2)增刪節(jié)點是否要做 Rebalance。

    保證均衡有如下幾個算法:

    • 1)輪詢:挨個將各個節(jié)點分配給客戶端,但會出現(xiàn)新增節(jié)點分配不均勻的情況;
    • 2)取模:類似于 HashMap,但也會出現(xiàn)輪詢的問題。當然也可以像 HashMap 那樣做一次 Rebalance,讓所有的客戶端重新連接。不過這樣會導致所有的連接出現(xiàn)中斷重連,代價有點大。由于 Hash 取模方式的問題帶來了一致性 Hash 算法,但依然會有一部分的客戶端需要 Rebalance;
    • 3)權重:可以手動調整各個節(jié)點的負載情況,甚至可以做成自動的,基于監(jiān)控當某些節(jié)點負載較高就自動調低權重,負載較低的可以提高權重。

    PS:筆者是采用輪詢 + 權重模式,盡量保證負載均衡。

    5.3 重連機制

    當應用在擴縮容或重啟升級時,在該節(jié)點上的客戶端怎么處理?

    由于設計有心跳機制,當心跳不通或監(jiān)聽連接斷開時,就認為該節(jié)點有問題了,就嘗試重新連接;如果客戶端正在發(fā)送消息,那么就需要將消息臨時保存住,等待重新連接上后再次發(fā)送。

    相關資料請閱讀:《Web端即時通訊實踐干貨:如何讓你的WebSocket斷網(wǎng)重連更快速?

    5.4 線程策略

    將連接服務里的IO線程與業(yè)務線程隔離,提升整體性能,原因如下:

    1)充分利用多核的并行處理能力:IO線程和業(yè)務線程隔離,雙方都可以并行處理網(wǎng)絡IO和業(yè)務邏輯,充分利用計算機多核并行計算能力,提升性能;

    2)故障隔離:業(yè)務線程處理多種業(yè)務消息,有IO密集型,也有 CPU 密集型,有些是純內存計算,不同的業(yè)務處理時延和故障率是不同的。如果把業(yè)務線程和IO線程合并,就會有如下問題:某類業(yè)務處理較慢,阻塞IO線程,導致其他處理較快的業(yè)務消息響應不及時;

    3)可維護性:IO線程和業(yè)務線程隔離之后,職責單一,有利于維護和定位問題。

    5.5 有狀態(tài)鏈接

    在這樣的場景中不像 HTTP 那樣是無狀態(tài)的,需要明確知道各個客戶端和連接的關系。

    比如需要向客戶端廣播群消息時,首先得知道客戶端的連接會話保存在哪個連接服務節(jié)點上,自然這里需要引入第三方中間件來存儲這個關系。

    通過由連接服務主動上報給群組服務來實現(xiàn),上報時機是客戶端接入和斷開連接服務以及周期性的定時任務。

    5.6 群組路由

    設想這樣一個場景:需要給群所有成員推送一條消息怎么做?

    通過群編號去前面的路由 Redis 獲取對應群的連接服務組,再通過 HTTP 方式調用連接服務,通過連接服務上的長連接會話進行真正的消息下發(fā)。

    5.7 消息流轉

    連接服務直接接收用戶的上行消息,考慮到消息量可能非常大,在連接服務里做業(yè)務顯然不合適,這里完全可以選擇 Kafka 來解耦,將所有的上行消息直接丟到 Kafka 就不管了,消息由群組服務來處理。

    6、消息的有序性設計

    6.1 亂序現(xiàn)象

    為什么要講消息順序,來看一個場景。假設群里有用戶A、用戶B、用戶C、用戶D,下面以 ABCD 代替,假設A發(fā)送了3條消息,順序分別是 msg1、msg2、msg3,但B、C、D看到的消息順序不一致。

    如下圖所示:

    這時B、C、D肯定會覺得A在胡言亂語了,這樣的產(chǎn)品用戶必定是不喜歡的,因此必須要保證所有接收方看到的消息展示順序是一致的。

    6.2 原因分析

    所以先了解下消息發(fā)送的宏觀過程:

    • 1)發(fā)送方發(fā)送消息;
    • 2)服務端接收消息;
    • 3)服務端返回 ACK 消息;
    • 4)服務端推送新消息或客戶端拉取新消息。

    在上面的過程中,都可能產(chǎn)生順序問題,簡要分析幾點原因:

    • 1)時鐘不一致:多個客戶端、服務端集群、DB集群,時鐘不能保證完全一致,因此不能用本地時間來決定消息順序;
    • 2)網(wǎng)絡傳輸:發(fā)送消息環(huán)節(jié),先發(fā)后至,到達服務器的順序可能是 msg2、msg1、msg3;
    • 3)多線程:服務器考慮性能、吞吐量,往往會在多處環(huán)節(jié)采用線程池、異步去提升整體速度,因此也會產(chǎn)生順序問題。

    6.3 解決方案

    1) 單用戶保持有序:

    通過上面的分析可以知道,其實無法保證或是無法衡量不同用戶之間的消息順序,那么只需保證同一個用戶的消息是有序的,保證上下文語義,所以可以得出一個比較樸素的實現(xiàn)方式:以服務端數(shù)據(jù)庫的唯一自增ID為標尺來衡量消息的時序,然后讓同一個用戶的消息處理串行化。

    那么就可以通過以下幾個技術手段配合來解決:

    • 1)發(fā)送消息使用 Websocket 發(fā)送,并且多次發(fā)送保持同一個會話,那么 tcp 協(xié)議就保證了應用層收到的消息必定是有序的;
    • 2)在應用程序內部處理時,涉及相關多線程的模塊,根據(jù) uid 進行 hash,匹配一個單線程的線程池,即同一個 uid 的消息永遠用同一個線程去處理,不同用戶之間仍是并行處理;
    • 3)在跨應用程序時,一般有2種處理方式:一是用 rpc 同步調用;二是利用消息中間件的全局有序;
    • 4)用戶端上做消息發(fā)送頻率限制,2次發(fā)送必須間隔1秒,能大大降低亂序的可能性了。

    2) 推拉結合:

    到這里基本解決了同一個用戶的消息可以按照他自己發(fā)出的順序入庫的問題,即解決了消息發(fā)送流程里第一、二步。

    第三、四步存在的問題是這樣的:

    A發(fā)送了 msg1、msg2、msg3,B發(fā)送了 msg4、msg5、msg6,最終服務端的入庫順序是msg1、msg2、msg4、msg3、msg5、msg6,那除了A和B其他人的消息順序需要按照入庫順序來展示,而這里的問題是服務端考量推送吞吐量,在推送環(huán)節(jié)是并發(fā)的,即可能 msg4 比 msg1 先推送到用戶端上,如果按照推送順序追加來展示,那么就與預期不符了,每個人看到的消息順序都可能不一致,如果用戶端按照消息的id大小進行比較插入的話,用戶體驗將會比較奇怪,突然會在2個消息中間出現(xiàn)一條消息。

    所以這里采用推拉結合方式來解決這個問題,具體步驟如下:

    • 1)用戶端發(fā)出消息,服務端將消息以群維度按照消息的入庫順序緩存在 Redis 有序 SET;
    • 2)服務端推送給用戶端新消息提醒,內容是該新消息的id;
    • 3)用戶端拉取消息,攜帶2個消息id,startId 和 endId,startId:本地最新的完整消息id;endId:服務端推送得到的新消息id;
    • 4)服務端返回2個消息id區(qū)間內的消息列表。
     

    舉例:上圖1表示服務端的消息順序,上圖2表示用戶端拉取消息時本地消息隊列和提醒隊列的變化邏輯。

    具體是:

    • 1)t1時刻用戶本地最新的完整消息是 msg1,即這條消息已經(jīng)完整展示給用戶;
    • 2)t2時刻收到服務端推送的 msg3 新消息提醒,放到提醒隊列,此時用戶看不到這條消息;
    • 3)t3時刻向服務端拉取消息詳情,請求參數(shù)為 startId:msg1,endId:msg3,服務端會按順序一起返回2個消息區(qū)間內的所有消息的詳情即 msg2、msg4、msg3,將消息詳情同步寫入到消息隊列,此時用戶可以看到刷新出3條消息;
    • 4)t4時刻用戶還會收到 msg2、msg4 的新消息提醒,用戶端校驗消息隊列已經(jīng)存在 msg2、msg4 的詳情,忽略該新消息提醒。

    通過推拉結合的方式可以保證所有用戶收到的消息展示順序一致。

    細心的讀者可能會有疑問:如果聊天信息流里有自己發(fā)送的消息,那么可能與其他的人看到的不一致,這是因為自己的消息展示不依賴拉取,需要即時展示,給用戶立刻發(fā)送成功的體驗,同時其他人也可能也在發(fā)送,最終可能比他先入庫,為了不出現(xiàn)信息流中間插入消息的用戶體驗,只能將他人的新消息追加在自己的消息后面。所以如果作為發(fā)送者,消息順序可能不一致,但是作為純接收者,大家的消息順序都是一樣的。

    相關資料請詳讀:

    1. 什么是IM系統(tǒng)的消息時序一致性?
    2. 如何保證IM實時消息的“時序性”與“一致性”?
    3. IM單聊和群聊中的在線狀態(tài)同步應該用“推”還是“拉”?
    4. 一個低成本確保IM消息時序的方法探討

    7、 消息的可靠性設計

    在IM系統(tǒng)中,消息的可靠性同樣非常重要,它主要體現(xiàn)在:

    1)消息不丟失:對發(fā)送人來說,必須保證消息能入庫;對接收者來說,不管是在線還是離線,都能保證收到。但是這里的不丟失,只是說以最大努力去保證,并不是說完全不丟失;

    2)消息不重復:這很容易理解,同一條消息不能重復出現(xiàn)。

    消息不丟失設計:

    1)傳輸協(xié)議保障:首先 TCP 是可靠的協(xié)議,能較大程度上保證消息不丟失;

    2)增加ACK機制:服務端在執(zhí)行完消息處理的所有流程后,給發(fā)送者發(fā)送 ACK;假如發(fā)送者在超時時間內沒有收到 ACK 消息,則進行一定次數(shù)的重試,重新發(fā)送;當重發(fā)次數(shù)超過預設次數(shù),就不再重發(fā),消息發(fā)送失敗;

    3)最終一致性:這是對接收者而言,如果某條新消息提醒因網(wǎng)絡等其他原因丟失,用戶沒有收到這條消息提醒,那么用戶就不會去拉消息詳情,在用戶視角就是沒有看到這條消息。但是當后續(xù)的新消息提醒送達時,可以依賴前面提到的拉取機制拿到一個區(qū)間內的消息列表,這里就包含了丟失的消息,因此能達到最終一致性。

    消息不重復設計:

    • 1)增加UUID:每條消息增加 UUID,由客戶端創(chuàng)建消息時生成,同一個用戶的消息 UUID 唯一;
    • 2)服務端:用戶 ID+UUID 在數(shù)據(jù)庫做聯(lián)合唯一索引,保證數(shù)據(jù)層面消息不重復;
    • 3)用戶端:進行兜底,構造一個map來維護已接收消息的id,當收到id重復的消息時直接丟棄。

    相關資料請詳讀:

    1. IM消息送達保證機制實現(xiàn)(一):保證在線實時消息的可靠投遞
    2. IM消息送達保證機制實現(xiàn)(二):保證離線消息的可靠投遞
    3. IM開發(fā)干貨分享:如何優(yōu)雅的實現(xiàn)大量離線消息的可靠投遞
    4. 融云技術分享:全面揭秘億級IM消息的可靠投遞機制
    5. 閑魚億級IM消息系統(tǒng)的離線推送到達率優(yōu)化
    6. 微信的海量IM聊天消息序列號生成實踐(算法原理篇)

    8、  消息未讀數(shù)的實現(xiàn)

    為了提醒用戶有新消息,需要給用戶展示新消息提醒標識,產(chǎn)品設計上一般有小紅點、具體的數(shù)值2種方式。

    具體數(shù)值比小紅點要復雜,這里分析下具體數(shù)值的處理方式,還需要分為初始打開群和已打開群2個場景。

    具體是:

    • 1)已打開群:可以完全依賴用戶端本地統(tǒng)計,用戶端獲取到新消息后,就將未讀數(shù)累計加1,等點進去查看后,清空未讀數(shù)統(tǒng)計,這個比較簡單;
    • 2)初始打開群:由于用戶端采用H5開發(fā),用戶端沒有緩存,沒有能力緩存最近的已讀消息游標,因此這里完全需要服務端來統(tǒng)計,在打開群時下發(fā)最新的聊天信息流和未讀數(shù),下面具體講下這個場景下該怎么設計。

    既然由服務端統(tǒng)計未讀數(shù),那么少不了要保存用戶在某個群里已經(jīng)讀到哪個消息,類似一個游標,用戶已讀消息,游標往前走。

    用戶已讀消息存儲表設計如下圖所示:

    游標offset采用定時更新策略,連接服務會記錄用戶最近一次拉取到的消息ID,定時異步上報批量用戶到群組服務更新 offset。

    該表第一行表示用戶1在 id=89 的群里,最新的已讀消息是id=1022消息,那么可以通過下面的SQL來統(tǒng)計他在這個群里的未讀數(shù):

    select count(1) from msg_info where groupId = 89 and id > 1022

    但是事情并沒這么簡單:一個用戶有很多群,每個群都要展示未讀數(shù),因此要求未讀數(shù)統(tǒng)計的程序效率要高,不然用戶體驗就很差,很明顯這個 SQL 的耗時波動很大,取決于 offset 的位置,如果很靠后,SQL 執(zhí)行時間會非常長。

    筆者通過2個策略來優(yōu)化這個場景:

    1)調整產(chǎn)品設計:未讀數(shù)最大顯示調整為99+。算是產(chǎn)品上的一個讓步,有很多產(chǎn)品也采用這個方案,所以用戶也是有這個心智的,99+表示“有很多新消息”,至于具體多少,是幾百、幾千很多時候不是特別重要。所以問題就變得簡單多了,只要計算游標是否在最新的100條消息以內還是以外;

    2)合理利用數(shù)據(jù)結構:因為有群內有很多人,每個人登錄的時候都需要統(tǒng)計,所以每次都去查 MySQL 是比較低效的,因此筆者的方案是在 Redis 里設計一個有界的ZSET結構。

    如上圖所示:每個群都會構建一個長度為100,score 和 member 都是消息ID,可以通過 zrevrank 命令得到某個 offset 的排名值,該值可以換算成未讀數(shù)。

    比如:用戶1在群89的未讀消息數(shù),'zrevrank 89 1022' = 2,也就是有2條未讀數(shù)。用戶2在群89的未讀數(shù),'zrevrank 89 890' = nil,那么未讀數(shù)就是99+。同時消息新增、刪除都需要同步維護該數(shù)據(jù)結構,失效或不存在時從 MySQL 初始化。

    9、 百萬人超大群聊的關鍵策略

    9.1 概述

    前面提到,設計目標是在同一個群里能支撐百萬人,從架構上可以看到,連接服務處于流量最前端,所以它的承載力直接決定了同時在線用戶的上限。

    影響它的因素有:

    • 1)服務器自身配置:內存、CPU、網(wǎng)卡、Linux 支持的最大文件打開數(shù);
    • 2)應用自身配置:應用本身啟動需要的內存,如 Netty 依賴的堆外內存,大量的本地緩存;
    • 3)性能要求:當連接數(shù)不斷變大時,消息分發(fā)的整體耗時肯定在不斷增加,因此要關注最慢的分發(fā)耗時要滿足即時性要求。

    結合以上情況,可以測試出固定配置服務器單點能支持的最大用戶連接數(shù),假如單機能支持20000個用戶連接,那么百萬在線連接,在連接服務層用50個服務的集群就能解決。

    9.2 消息風暴

    當同時在線用戶數(shù)非常多,例如百萬時,會面臨如下幾個問題:

    1)消息發(fā)送風暴:極端情況下,用戶同時發(fā)送消息,假設服務端承載住了這些流量,那么瓶頸其實在用戶端,第一用戶端會經(jīng)歷網(wǎng)絡風暴,網(wǎng)卡帶寬能否支撐是一個大問題;第二假設網(wǎng)卡能通過這些流量,用戶端上百萬條消息該如何展示,要是瞬間刷出這些消息,用戶端 CPU能否撐住又是個問題,即使能抗住用戶體驗也很糟糕,根本就看不清消息,一直在飛速刷屏。因此服務端可以在發(fā)送消息風暴時做好限流、丟棄策略,給到用戶友好的提示;

    2)消息提醒風暴:一條新消息的產(chǎn)生,就要推送提醒消息百萬次,對服務器來說,要考量整體推送完成的時效性,如果時效性差,對有些用戶來說,就是消息需要較長時間才刷出來,出現(xiàn)明顯的延遲。新消息持久化后,群組服務 HTTP 回調一組連接服務,單群百萬在線用戶,需要50臺連接服務集群,那么回調50次,為了保證時效性,因此這里要并發(fā)回調,并設置合理的線程池,然后連接服務收到回調后也需要并發(fā)完成對群用戶的新消息提醒推送;

    3)消息拉取風暴:連接服務收到拉取消息事件,需要去群組服務獲取消息詳情,QPS 就非常高了,理論上集群達到 100wQPS,20臺群組服務,那么每臺群組服務就是 5wQPS。這里的策略是在鏈路前端連接服務上進行流量過濾,因為用戶都是請求同一個群的同一條消息或附近的消息,那么就可以在連接服務里設計群消息的本地緩存,所有用戶都只從本地緩存里讀,如果本地緩存里沒有,就放一個線程去群組服務請求加載緩存,其他線程同步等待,這樣就大大降低了打到群組服務的 QPS。

    9.3 消息壓縮

    如果某一個時刻,推送消息的數(shù)量比較大,且群同時在線人數(shù)比較多的時候,連接服務層的機房出口帶寬就會成為消息推送的瓶頸。

    做個計算,百萬人在線,需要5臺連接服務,一條消息1KB,一般情況下,5臺連接服務集群都是部署在同一個機房,那么這個機房的帶寬就是1000000*1KB=1GB,如果多幾個超大群,那么對機房的帶寬要求就更高,所以如何有效的控制每一個消息的大小、壓縮每一個消息的大小,是需要思考的問題。

    經(jīng)過測試:使用 protobuf 數(shù)據(jù)交換格式,平均每一個消息可以節(jié)省43%的字節(jié)大小,可以大大節(jié)省機房出口帶寬(詳讀《Protobuf從入門到精通,一篇就夠!》)。

    9.4 塊消息

    超大群里,消息推送的頻率很高,每一條消息推送都需要進行一次IO系統(tǒng)調用,顯然會影響服務器性能,可以采用將多個消息進行合并推送。

    主要思路:以群為維度,累計一段時間內的消息,如果達到閾值,就立刻合并推送,否則就以勻速的時間間隔將在這個時間段內新增的消息進行推送。

    時間間隔是1秒,閾值是10,如果500毫秒內新增了10條消息,就合并推送這10條消息,時間周期重置;如果1秒內只新增了8條消息,那么1秒后合并推送這8條消息。

    這樣做的好處如下:

    • 1)提升服務器性能:減少IO系統(tǒng)調用,減少用戶態(tài)與內核態(tài)之前的切換;
    • 2)減少傳輸量:合并消息后,可以減少傳輸多余的消息頭,進一步壓縮消息大小;
    • 3)提升用戶體驗:一定程度上能減小消息風暴,消息渲染的節(jié)奏比較均勻,帶給用戶更好的體驗。

    10、 本文小結

    在本文中,筆者介紹了從零開始搭建一個生產(chǎn)級百萬級群聊的一些關鍵要點和實踐經(jīng)驗,包括通信方案選型、消息存儲、消息順序、消息可靠性、高并發(fā)等方面,但仍有許多技術設計未涉及,比如冷熱群、高低消息通道會放在未來的規(guī)劃里。

    IM開發(fā)業(yè)界沒有統(tǒng)一的標準,不同的產(chǎn)品有適合自己的技術方案,希望本文能夠帶給讀者更好地理解和應用這些技術實踐,為構建高性能、高可靠性的群聊系統(tǒng)提供一定的參考。

    11、 參考資料

    [1]新手入門貼:史上最全Web端即時通訊技術原理詳解

    [2]Web端即時通訊技術盤點:短輪詢、Comet、Websocket、SSE

    [3]網(wǎng)頁端IM通信技術快速入門:短輪詢、長輪詢、SSE、WebSocket

    [4]搞懂現(xiàn)代Web端即時通訊技術一文就夠:WebSocket、socket.io、SSE

    [5]理論聯(lián)系實際:從零理解WebSocket的通信原理、協(xié)議格式、安全性

    [6]Web端即時通訊實踐干貨:如何讓你的WebSocket斷網(wǎng)重連更快速?

    [7]WebSocket從入門到精通,半小時就夠!

    [8]一套分布式IM即時通訊系統(tǒng)的技術選型和架構設計

    [9]微信團隊分享:來看看微信十年前的IM消息收發(fā)架構,你做到了嗎

    [10]攜程技術分享:億級流量的辦公IM及開放平臺技術實踐

    [11]轉轉平臺IM系統(tǒng)架構設計與實踐(一):整體架構設計

    [12]一套億級用戶的IM架構技術干貨(下篇):可靠性、有序性、弱網(wǎng)優(yōu)化等

    [13]從新手到專家:如何設計一套億級消息量的分布式IM系統(tǒng)

    [14]企業(yè)微信的IM架構設計揭秘:消息模型、萬人群、已讀回執(zhí)、消息撤回等

    [15]融云技術分享:全面揭秘億級IM消息的可靠投遞機制

    [16]如何保證IM實時消息的“時序性”與“一致性”?

    [17]IM單聊和群聊中的在線狀態(tài)同步應該用“推”還是“拉”?

    [18]IM群聊消息如此復雜,如何保證不丟不重?

    [19]現(xiàn)代IM系統(tǒng)中聊天消息的同步和存儲方案探討

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

    [21]一套高可用、易伸縮、高并發(fā)的IM群聊、單聊架構方案設計實踐

    [22]網(wǎng)易云信技術分享:IM中的萬人群聊技術方案實踐總結

    [23]微信直播聊天室單房間1500萬在線的消息架構演進之路

    [24]海量用戶IM聊天室的架構設計與實踐

    [25]IM技術干貨:假如你來設計微信的群聊,你該怎么設計?

    [26]百萬級成員實時社群技術實現(xiàn)(消息系統(tǒng)篇)

    (本文已同步發(fā)布于:http://www.52im.net/thread-4789-1-1.html)



    作者:Jack Jiang (點擊作者姓名進入Github)
    出處:http://www.52im.net/space-uid-1.html
    交流:歡迎加入即時通訊開發(fā)交流群 215891622
    討論:http://www.52im.net/
    Jack Jiang同時是【原創(chuàng)Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
    本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: 国产在线98福利播放视频免费| 91av免费观看| 国产yw855.c免费视频| 国产亚洲玖玖玖在线观看| 成人黄色免费网站| 亚洲日本在线免费观看| 免费看男女下面日出水来| 亚洲国产电影在线观看| 一本无码人妻在中文字幕免费 | 亚洲视频在线观看视频| 中文字幕在线免费观看| 亚洲一区二区三区免费观看| 在线观看视频免费完整版| 亚洲欧美精品午睡沙发| 免费看男女下面日出水视频| 人妻巨大乳hd免费看| 好看的电影网站亚洲一区| 免费A级毛片无码A∨中文字幕下载| 亚洲今日精彩视频| 欧美大尺寸SUV免费| 国产精品亚洲五月天高清| 亚洲一区日韩高清中文字幕亚洲| 国产一级黄片儿免费看| 亚洲精品人成电影网| 日韩在线视频免费看| 中文字幕免费在线播放| 久久精品国产亚洲AV大全| 麻豆国产人免费人成免费视频| 特a级免费高清黄色片| 亚洲av网址在线观看| 欧美在线看片A免费观看| 一级毛片无遮挡免费全部| 亚洲成a人片在线观看中文动漫| 免费A级毛片无码无遮挡内射| 黑人粗长大战亚洲女2021国产精品成人免费视频 | 免费播放国产性色生活片| 久久青青草原亚洲AV无码麻豆| 成人免费看片又大又黄| 三级毛片在线免费观看| 日韩亚洲人成在线| 亚洲日韩精品射精日|