Jack Jiang

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

          本文由網(wǎng)易云信資深服務(wù)器開發(fā)工程師曹佳俊分享,原題“深度剖析“圈組”消息系統(tǒng)設(shè)計 | “圈組”技術(shù)系列文章”,為了提升內(nèi)容品質(zhì),本文有修訂和刪節(jié)。

          1、引言

          鑒于實時社群產(chǎn)品Discord在IM垂直應用領(lǐng)域的爆火,類似的需求越來越多,云信的“圈組”就是針對這種應用場景的技術(shù)產(chǎn)品。

          “圈組”產(chǎn)品發(fā)布后獲得了很大的關(guān)注,很多云信用戶在接入SDK的同時對于“圈組”的底層技術(shù)細節(jié)和原理也非常關(guān)注,為此我們決定推出“圈組”相關(guān)的技術(shù)文章,分享云信在“圈組”技術(shù)設(shè)計上的一些思考和實踐。

          本文是序列文章的第2篇,將要分享的是云信的實時社群產(chǎn)品“圈組”(“圈組”云信的類Discord產(chǎn)品實現(xiàn)方案)的消息系統(tǒng)技術(shù)設(shè)計實踐。

           
           技術(shù)交流:

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

          2、系列文章

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

          3、作者介紹

          曹佳俊:網(wǎng)易云信資深服務(wù)器開發(fā)工程師,畢業(yè)于中國科學院,碩士畢業(yè)后加入網(wǎng)易,負責云信 IM/RTC 信令等業(yè)務(wù)的服務(wù)器開發(fā)。專注于即時通訊、RTC 信令以及相關(guān)中間件等技術(shù),是云信開源項目 Camellia 的作者。

          4、“圈組”的技術(shù)特點

          在介紹“圈組”的技術(shù)細節(jié)之前,我們先了解一下圈組的技術(shù)特點。

          “圈組”產(chǎn)品最大的特點是什么?

          • 1)首先:是 server/channel 的二級結(jié)構(gòu);
          • 2)其次:是構(gòu)建在二級結(jié)構(gòu)之上的大規(guī)模社群(單個 server 數(shù)十萬甚至上百萬成員);
          • 3)以及:使用復雜的身份組系統(tǒng)來管理如此規(guī)模的社群組織和成員。

          那么對于這樣一個新穎的 IM 系統(tǒng),在技術(shù)上應該如何實現(xiàn)呢?

          5、“圈組”和傳統(tǒng)IM群組的技術(shù)差異

          5.1概述

          一種簡單的思路是改造已有的 IM 系統(tǒng),對于“圈組”這樣的類 Discord 社群,第一個思路是拓展我們的群組功能,猛一看在很多方面確實挺像的。

          我們做了個簡單的對比:

          從上面的表格可以看到,“圈組”和群組最大的不同:

          • 1)是容量的區(qū)別;
          • 2)是二級結(jié)構(gòu)。

          其他的諸如身份組、個性化推送策略,似乎只要適配的做一下就可以了。

          那么是不是只要想辦法提升一下群組的容量,再在業(yè)務(wù)層封裝一下二級結(jié)構(gòu)就可以了呢?

          答案顯然是否定的,或者至少說基于群組去擴展不是一個很好的想法。

          5.2二級結(jié)構(gòu)的差異

          首先是二級結(jié)構(gòu)。

          在類 Discord 的二級結(jié)構(gòu)中,成員的管理在 server 層,而 channel 成員是繼承自 server 的,而且在 channel 之上還有很多可見性的配置(我們的“圈組”提供了黑白名單機制,而Discord 則提供了查看頻道權(quán)限)。

          在這種機制之下,任何 server 層面的成員變動,都可能影響全部或者部分頻道的成員列表。

          面對這種復雜的結(jié)構(gòu),群組有兩種思路去實現(xiàn):

          • 1)一種是 N 個群,邏輯上隸屬于同一個 server;
          • 2)一種是一個群映射為一個 server。

          不管哪種方式,先不說消息投遞這塊的邏輯,僅成員管理上邏輯的耦合和交織的復雜性,足以勸退任何人。

          5.3容量的差異

          常規(guī)IM群組的容量一般只有數(shù)百,最多可以擴展到數(shù)千。

          對于IM群組成員的管理,我們一般采取全量+增量同步相結(jié)合的方案,客戶端和服務(wù)器映射到相同的群組鏡像(群信息+群成員等)。此時很多操作,例如群成員的展示、檢索,消息的艾特等,都可以基于純客戶端進行。

          而“圈組”要求幾十萬甚至上百萬的容量,顯然客戶端無法一次性獲取到所有成員,如果你一次性加入多個 server,那成員的數(shù)量將更加膨脹。

          因此在“圈組”這種大規(guī)模社群的設(shè)計中,很多邏輯都會轉(zhuǎn)向云端,此時不管是 SDK 還是服務(wù)器,均需要修改原有的設(shè)計邏輯。

          5.4消息規(guī)模差異

          此外,大規(guī)模社群帶來的是消息爆炸。

          在原有的IM群組設(shè)計中,假設(shè)一個人同時加入了 1000 個群,那么這 1000 個群內(nèi)的所有消息均會在第一時間下發(fā)給給客戶端。

          但是在一般的業(yè)務(wù)場景中,不會所有的群都同時活躍,假設(shè)這 1000 個群變成了 1000 個服務(wù)器/頻道,作為一種社群組織,同時活躍的可能性將大大增加,而且每個服務(wù)器/頻道的人數(shù)遠遠超過普通的群組,疊加之后帶來的消息爆炸現(xiàn)象在原有的群組體系中將帶來極大的壓力。

          壓力包括多方面:

          • 1)首先是海量消息的存儲壓力;
          • 2)其次是海量消息在線廣播/離線消息推送帶來的帶寬和服務(wù)器壓力;
          • 3)以及客戶端在面對大量消息沖擊時如何有效地接受和合理的展示。

          5.5小結(jié)

          除了容量、二級結(jié)構(gòu)、消息規(guī)模,包括身份組、成員管理、個性化推送策略等等都存在巨大差異。

          是否真的適合在群組中添加這些復雜邏輯呢,強行綁定在一起會不會既沒有一個好用的類 Discord 平臺,也使得原始的群組功能繁雜,反而降低了易用性呢?

          經(jīng)過上面的一些分析,我們基本可以得出一個結(jié)論:在已有的群組基礎(chǔ)上擴展來實現(xiàn)一個類 Discord 功能的社群,顯然不是一個很好的思路。

          那么還有其他“捷徑”嗎?

          IM聊天室也是一個潛在的選項,聊天室的一大特點就是支持超大規(guī)模同時在線(參見《千萬級實時直播彈幕的技術(shù)實踐》),容量似乎已經(jīng)不是問題,但是當考慮添加其他一些強社交關(guān)系的特性時(如成員、身份組等)就顯得有點為難了,聊天室本身就是來去自如的一個開放空間,這個和圈組的產(chǎn)品本身定位互相沖突的。

          因此基于聊天室擴展的方案也基本 pass 掉了。

          6、“圈組”的技術(shù)難點

          基于上述種種的思考和討論,最終選擇脫離已有 IM 體系,從零研發(fā)一套全新的社群方案“圈組”,“圈組”不是一個簡單的 IM 功能,而是一套可以獨立運行的 IM 系統(tǒng)。

          經(jīng)過上面的討論,相信大家對“圈組”本身的技術(shù)特點和難點也有所理解。

          可以歸納為以下幾點:

          • 1)二級結(jié)構(gòu)下成員無上限的社交關(guān)系系統(tǒng)設(shè)計;
          • 2)超大社群下消息系統(tǒng)設(shè)計;
          • 3)復雜高效的身份組系統(tǒng)設(shè)計;

          7、“圈組”技術(shù)實現(xiàn)之整體架構(gòu)  

          “圈組”整體架構(gòu):

          上面展示了“圈組”服務(wù)整體的架構(gòu)。

          可以看到整個“圈組”服務(wù)是一個分層的架構(gòu):

          • 1)首先是接入層,包括 LBS 服務(wù)和長鏈接服務(wù)器以及 API 網(wǎng)關(guān),對應客戶端 SDK 和用戶服務(wù)器;
          • 2)后面是網(wǎng)絡(luò)層,包括大網(wǎng) WE-CAN 和協(xié)議路由服務(wù);
          • 3)其次是服務(wù)層,劃分了多個服務(wù)模塊,每個模塊都包括多個微服務(wù);
          • 4)最后是基礎(chǔ)設(shè)施。

          8、“圈組”技術(shù)實現(xiàn)之消息系統(tǒng)架構(gòu)

          這其中和消息系統(tǒng)相關(guān)聯(lián)的包括接入層、網(wǎng)絡(luò)層、以及后端的登錄/訂閱/消息/檢索等模塊。

          基本架構(gòu)如下:

          消息系統(tǒng)中第一個要討論的點就是消息的存儲和分發(fā)方式,包括在線廣播、離線推送、歷史消息三個維度。

          下面幾節(jié)我們將對消息系統(tǒng)中各模塊分別展開介紹。

          9、“圈組”消息系統(tǒng)技術(shù)實現(xiàn)1:在線廣播

          對于一般的IM群組來說,在線廣播的一般過程是這樣的:依次查詢?nèi)航M里的所有人的在線狀態(tài),如果在線,則將消息發(fā)送給對應的長鏈接服務(wù)器。

          顯然這種機制無法復制到“圈組”,因為在“圈組”的一個服務(wù)器里可能存在超過 100w 的人。

          此外:IM聊天室的廣播模式也不能直接復用,因為在聊天室架構(gòu)中,每個長鏈接映射到一個聊天室,因此當你登錄到某個聊天室的時候,你只會收到該聊天室的消息。而對于“圈組”來說,每個用戶會同時加入多個服務(wù)器/頻道,而且會同時收到多個服務(wù)器/頻道的消息。

          針對“圈組”的上述特點:我們設(shè)計了消息訂閱模式,也就是用戶登錄之后,需要訂閱感興趣的相關(guān)服務(wù)器/頻道,服務(wù)器會記錄下這個訂閱信息。當有新消息的時候,服務(wù)器通過訂閱關(guān)系(而不是在線狀態(tài))查詢到需要廣播的列表,通過這種方式就不再需要遍歷服務(wù)器/頻道里的所有用戶。

          但是當一個服務(wù)器/頻道里在線人數(shù)非常多的時候,這個訂閱關(guān)系仍然是巨大的。

          為此:我們設(shè)計了一種兩層訂閱模型,即所有的訂閱關(guān)系會保存在長鏈接服務(wù)器上(QChatLink/QChatWebLink),同時長鏈接服務(wù)器會定時發(fā)送心跳給后端的訂閱服務(wù)器,心跳信息相比原始的訂閱信息會大大簡化,比如長鏈接服務(wù)器上會記錄賬號 A 訂閱了某個頻道 A 的消息,如果有 1w 個賬號,則有 1w 條訂閱記錄,而心跳信息里只會上報有 1w 個人訂閱了某個頻道 A 的消息,具體的賬號列表則被精簡掉了。當一條消息需要廣播時,消息服務(wù)會訪問訂閱服務(wù),獲取到該服務(wù)器/頻道被訂閱的長鏈接服務(wù)器列表,并依次給該列表中的長鏈接服務(wù)器發(fā)送消息下發(fā)通知,長鏈接服務(wù)器收到通知后會根據(jù)訂閱詳情再廣播給所有客戶端。

          此外:我們還提供了多種訂閱類型,當你非常關(guān)心某個頻道消息時(比如頁面正停留在該頻道),此時你可以訂閱該頻道的消息。對于其他頻道,如果你僅僅需要知道該頻道有多少條未讀消息(或者有無未讀消息),則可以選擇訂閱該頻道的未讀計數(shù)(或者未讀狀態(tài)),此時服務(wù)下發(fā)時僅會廣播精簡的消息體用于維護客戶端未讀計數(shù),并且當未讀計數(shù)達到一定閾值之后(比如 99+),服務(wù)器可以選擇不再下發(fā)任何通知消息而不影響用戶體驗。

          通過上文介紹的消息訂閱模型,極大地提高了超大型的圈組頻道/服務(wù)器消息在線廣播的效率,降低了服務(wù)器壓力。

          除此之外:我們還設(shè)計了針對小型頻道的特殊策略,對于小型頻道,即使不訂閱,服務(wù)器也會下發(fā)消息通知給頻道里所有人,從而減輕端側(cè)消息訂閱模型的維護成本。針對消息訂閱機制本身,后續(xù)我們也會根據(jù)不同的業(yè)務(wù)場景,提供更多一站式的策略來幫助降低接入成本,提升整體的易用性。

          10、“圈組”消息系統(tǒng)技術(shù)實現(xiàn)2:離線推送

          在強社交的場景下,離線消息推送對于維持用戶粘性+提升產(chǎn)品體驗有很大的作用。

          從技術(shù)角度看的話,主要解決2個問題:

          1)第一個是超大型服務(wù)器/頻道的消息推送的效率問題;

          2)另一個是提供足夠豐富的推送策略來幫助 C 端用戶,避免被過量的推送消息給打擾。

          針對第一個問題,我們針對不同規(guī)模的服務(wù)器/頻道采取了不同的策略:

          • 1)對于小型頻道:采用類似于群組的消息推送模型;
          • 2)對于大型頻道:對于每一條需要推送的消息,會根據(jù)目標用戶的 ID 進行任務(wù)分片,多個節(jié)點并行操作,提高推送效率。

          此外:分片會采用一致性策略,保證單個用戶固定為某些節(jié)點,從而提高緩存命中效率。

          針對第二個問題,推送策略可以用以下幾句話來描述:

          • 1)既關(guān)注促活,又保證不打擾;
          • 2)大型 server 是游樂場,只推送與用戶相關(guān)的重要消息(如 @消息);
          • 3)小型 server 是與朋友相處的小天地,支持消息的全部推送。

          并且:未來用戶還可以自定義消息的高低優(yōu)先級,并搭配不同的推送配置(如不同的免打擾配置等),如下圖所示。

          11、“圈組”消息系統(tǒng)技術(shù)實現(xiàn)3:歷史消息

          歷史消息的存儲在“圈組”的場景中也需要一些特別的設(shè)計。

          同樣以傳統(tǒng)IM群組為例,一般來說消息的存儲方式有兩種,寫擴散和讀擴散。在小型的IM群組或者多人會話中,寫擴散模式可以簡化設(shè)計,但是當群組規(guī)模擴大到一定程度(如萬人群),讀擴散就成了選擇。

          而對于“圈組”這種單個服務(wù)器可能上百萬人的“群組”中,除了常規(guī)的讀擴散之外,我們還設(shè)計了多級緩存的結(jié)構(gòu)來應對海量的讀請求。

          基本的存儲架構(gòu)大致如下:

          消息的存儲主要包括兩部分:

          • 1)一部分是消息本身;
          • 2)一部分是未讀計數(shù)。

          首先是寫入:對于上述兩者,我們都會使用中心化的緩存服務(wù)器來存儲最近的數(shù)據(jù),并使用異步+批量+聚合等手段,通過 MQ 異步落庫,從而平衡寫入效率(單條寫入性能低)和寫入讀取延遲(異步寫入有延遲)的問題,并且針對不同數(shù)據(jù)類型的特點,我們也選擇了不同的存儲方案(歷史消息使用分布式時間序列數(shù)據(jù)庫,未讀計數(shù)使用分布式 k-v 數(shù)據(jù)庫),最大化地提升消息存儲和查詢的性能和效率。

          有寫就有讀,針對讀取操作:

          • 1)所有最近的消息和未讀計數(shù)均會存儲在中心化緩存中,并通過先進先出和緩存過期等不同的策略來確保緩存中存儲的永遠是最新和最熱的數(shù)據(jù);
          • 2)對于消息 ID 和消息內(nèi)容本身,中心化緩存中也會有不同的數(shù)據(jù)結(jié)構(gòu)和過期策略,來平衡緩存命中率和緩存容量消耗;
          • 3)當緩存過期了,如果有關(guān)聯(lián)的讀寫請求,將會觸發(fā)緩存的重建,以保證緩存的命中率始終保持在較高水位;
          • 4)當有高頻的讀請求,還會觸發(fā)熱點 cache 的檢測,并將一部分讀請求下沉到各個計算節(jié)點的內(nèi)存中,以應對突發(fā)流量的沖擊。

          上述針對“圈組”的特別設(shè)計,消息存儲系統(tǒng)可以應對幾十數(shù)百人的小型圈組頻道,也可以從容應對上百萬的超大型頻道。

          12、相關(guān)資料

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

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

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

          [4] 融云IM技術(shù)分享:萬人群聊消息投遞方案的思考和實踐

          [5] 微信直播聊天室單房間1500萬在線的消息架構(gòu)演進之路

          [6] 百萬人在線的直播間實時聊天消息分發(fā)技術(shù)實踐

          [7] 千萬級實時直播彈幕的技術(shù)實踐

          [8] 深度解密釘釘即時消息服務(wù)DTIM的技術(shù)設(shè)計

          [9] 深度揭密RocketMQ在釘釘IM系統(tǒng)中的應用實踐

          [10] 一套億級用戶的IM架構(gòu)技術(shù)干貨(上篇):整體架構(gòu)、服務(wù)拆分等

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

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

          (本文已同步發(fā)布于:http://www.52im.net/thread-4321-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】的作者,可前往下載交流。
          本博文 歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處(也可前往 我的52im.net 找到我)。


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


          網(wǎng)站導航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 东乡族自治县| 武乡县| 牟定县| 长汀县| 凤山市| 甘德县| 南木林县| 桦南县| 开鲁县| 宜宾县| 麻阳| 北安市| 瑞安市| 樟树市| 景德镇市| 常宁市| 滨州市| 古浪县| 洪洞县| 嵊州市| 报价| 平顺县| 红原县| 田林县| 石台县| 温州市| 高陵县| 应城市| 如东县| 兴安盟| 合阳县| 绍兴县| 娄底市| 泾源县| 南康市| 衡阳市| 田林县| 水富县| 岳西县| 龙门县| 博白县|