IM群聊消息的已读未读功能在存储空间方面的实现思路探讨
1、引言
IM系統(tǒng)中,特別是在企業(yè)應(yīng)用場(chǎng)景下,消息的已讀未讀狀態(tài)是一個(gè)強(qiáng)需求。
以阿里的釘釘為例,釘釘?shù)漠a(chǎn)品定位是用于商務(wù)交流,其“強(qiáng)制已讀回執(zhí)”功能,讓職場(chǎng)人無(wú)法再“假裝不在線(xiàn)”、“假裝沒(méi)收到”。更有甚者,釘釘?shù)娜毫?ldquo;強(qiáng)制已讀回執(zhí)”功能,甚至能夠知道誰(shuí)讀了消息,誰(shuí)沒(méi)有讀消息(老板的福音?。?。
▲ 釘釘里的群聊消息已讀未讀功能效果
功能看起來(lái)很酷,但用起來(lái)是一言難盡(上班族心里苦....)。實(shí)際上,技術(shù)實(shí)現(xiàn)也并不容易。
那么,對(duì)于已讀未讀狀態(tài):
1)如果是私聊:消息的閱讀狀態(tài)比較容易實(shí)現(xiàn),在性能和存儲(chǔ)上也不存在問(wèn)題;
2)如果是群聊:考慮到存儲(chǔ)和處理性能,特別當(dāng)處于一個(gè)云環(huán)境時(shí),如何高效地處理群聊的已讀未讀狀態(tài)是一個(gè)非常值得探討的話(huà)題。
這里提到的“高效”含3個(gè)方面:
1)存儲(chǔ)空間;
2)處理速度;
3)傳輸字節(jié)數(shù)。
本文將從服務(wù)端的角度來(lái)探討已讀未讀狀態(tài),在具體的技術(shù)實(shí)現(xiàn)上對(duì)于存儲(chǔ)空間占用方面的思路差異。能力有限,權(quán)當(dāng)個(gè)人筆記,歡迎交流。
學(xué)習(xí)交流:
- 即時(shí)通訊/推送技術(shù)開(kāi)發(fā)交流5群:215477170[推薦]
- 移動(dòng)端IM開(kāi)發(fā)入門(mén)文章:《新手入門(mén)一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM》
本文已同步發(fā)布于“即時(shí)通訊技術(shù)圈”公眾號(hào),歡迎關(guān)注:
▲ 本文在公眾號(hào)上的鏈接是:https://mp.weixin.qq.com/s/yUkKPOBsdqLlxiFrGmwFRQ,原文鏈接是:http://www.52im.net/thread-3054-1-1.html
2、內(nèi)容點(diǎn)評(píng)
在收錄本文前,Jack Jiang建議原作者對(duì)某些具體的技術(shù)點(diǎn)進(jìn)行更深入的分享,但因作者工作較忙,本文中的某些關(guān)鍵技術(shù)點(diǎn)未來(lái)的及作進(jìn)一步展開(kāi)。
所以,本文可以作為IM聊天消息(主要是群聊)中已讀未讀功能的基本實(shí)現(xiàn)思路方面的參考,但不建議盲目迷信文中的結(jié)論或方案,避免被一些不夠具體的技術(shù)指標(biāo)而誤導(dǎo)。
3、相關(guān)文章
如果你還想了解更多有關(guān)IM群聊中已讀未讀功能的實(shí)現(xiàn)邏輯,可以進(jìn)一步閱讀干貨文章《IM群聊消息的已讀回執(zhí)功能該怎么實(shí)現(xiàn)?》(強(qiáng)烈推薦)。
如果你對(duì)IM中的已讀未讀功能有產(chǎn)品方面的痛點(diǎn)困惑,可以參考一下微信對(duì)已讀未讀功能的設(shè)計(jì)定位,詳見(jiàn)《IM熱門(mén)功能思考:為什么微信里沒(méi)有消息“已讀”功能?》。
更多IM群聊技術(shù)方面的文章詳見(jiàn)文本附錄部分。
4、已讀未讀狀態(tài)交互流程
發(fā)送者發(fā)送的IM聊天消息,在接收者閱讀消息后,是否要求閱讀者通知已讀,可能是由系統(tǒng)配置、組織配置、群組配置等決定,也可能由發(fā)送者根據(jù)業(yè)務(wù)需求決定。以下的討論,均假設(shè)消息需要已讀未讀狀態(tài)。
客戶(hù)端與服務(wù)端之間,關(guān)于閱讀狀態(tài)的命令只需3個(gè),每個(gè)命令含請(qǐng)求和應(yīng)答。
4.1 通知消息已讀(私聊、群聊通用)
當(dāng)小寶閱讀了一條或若干條消息,需向服務(wù)端發(fā)送消息已讀通知:“眾愛(ài)卿發(fā)的x+y+z消息,朕已閱”。
服務(wù)端收到小寶的已讀通知時(shí),需完成以下事項(xiàng):
1)存儲(chǔ)消息的已讀狀態(tài);
2)返回應(yīng)答給小寶;
3)向已讀列表的消息的原始發(fā)送者通知消息已讀。
對(duì)于第“3)”步:
1)私聊的場(chǎng)合,比較好理解,就是發(fā)送給私聊的對(duì)方;
2)群聊的場(chǎng)合,可很不一樣:因?yàn)樾毎l(fā)送的已讀消息列表,可能是由眾愛(ài)卿發(fā)送的。考慮這種假設(shè):張三、李四、王五發(fā)出的群聊消息,被小寶一下都閱讀了,那么小寶發(fā)出的已讀通知包含的消息列表,需要被IMS分解成3個(gè)已讀通知(3個(gè)不同的消息列表),分別通知給張三、李四、王五,通知內(nèi)容是“愛(ài)卿(不含'"眾")發(fā)的這些消息,朕已閱”。
下面是大致的邏輯流程圖:
4.2 查詢(xún)消息的未讀人數(shù)(私聊、群聊通用)
消息的發(fā)送者,加載消息列表到聊天窗口時(shí),可能需要展示消息是否被已讀。
對(duì)群聊而言,顯示的信息可能是n人未讀的提示,那么需要向服務(wù)端查詢(xún)消息的未讀人數(shù),由于客戶(hù)端可能在UI顯示自己發(fā)出的多條消息,需支持一次請(qǐng)求查詢(xún)多條消息。
以未讀人數(shù)的方式來(lái)表示消息的閱讀狀態(tài),統(tǒng)一了私聊、群聊的查詢(xún),使得客戶(hù)端-服務(wù)端間的接口更簡(jiǎn)單,同時(shí)使客戶(hù)端的實(shí)現(xiàn)邏輯更統(tǒng)一。
就像下面這樣:
1)對(duì)于私聊:如果未讀人數(shù)n>0,表示消息未讀;
2)對(duì)于群聊:直接顯示n人未讀即可,當(dāng)然,當(dāng)n等于0時(shí)表示全部已讀。
4.3 查詢(xún)?nèi)合⒌囊炎x、未讀人員清單(群聊)
當(dāng)客戶(hù)端希望顯示某一條群聊消息的已讀、未讀人員列表,需向服務(wù)端發(fā)起查詢(xún)。
大致的邏輯流程圖如下:
5、幾種具體的已讀未讀狀態(tài)存儲(chǔ)思路探討
5.1 基本約定
群聊的閱讀狀態(tài)比私聊復(fù)雜,因此這里著重討論群聊的閱讀狀態(tài)。
假設(shè)群成員數(shù)是n,各個(gè)客戶(hù)端立即IM服務(wù)端發(fā)送已讀通知。服務(wù)端需存儲(chǔ)每個(gè)人的閱讀狀態(tài),包括那些未讀的成員。由于群的成員清單可能變化,比如今天增加了一個(gè)成員,則昨天發(fā)的消息、與今天發(fā)的消息,其接收者列表不一樣。
即:
1)同一個(gè)群的不同消息,對(duì)應(yīng)的接收者列表可能不一樣。
2)換言之,每一條消息都需要記錄完整的接收者列表和已讀人員列表。
為了方便討論,本章假設(shè)群成員有640人為前提。
5.2 存儲(chǔ)思路1
每一條消息都維護(hù):
1)接收人員列表receiver_list;
2)已讀人員列表read_list。
具體是:
1)IM Server收到一條消息時(shí),用全體群成員構(gòu)建receiver_list;
2)IM Server收到群成員對(duì)這條消息的已讀通知時(shí),將此成員加入到read_list。
客戶(hù)端獲取此消息的數(shù)據(jù):
1)當(dāng)需要獲取未讀人數(shù)時(shí),用receiver_list的個(gè)數(shù)減去read_list的個(gè)數(shù);
2)當(dāng)需要獲取已讀、未讀人員列表時(shí),需用receiver_list減去read_list得到未讀人員列表。
那么,思路1每條消息的存儲(chǔ)空間是:
640個(gè)ID + 不定數(shù)量的已讀人員ID
5.3 存儲(chǔ)思路2
每一條消息維護(hù):
1)未讀人員列表unread_list;
2)已讀人員列表read_list。
具體是:
1)IM Server收到一條消息時(shí),用全體群成員構(gòu)建unread_list;
2)IM Server收到群成員對(duì)這條消息的已讀通知時(shí),將此成員從unread_list移出,同時(shí)加入到read_list。
客戶(hù)端獲取此消息的數(shù)據(jù):
1)當(dāng)需要獲取未讀人數(shù)時(shí),直接計(jì)算unread_list的個(gè)數(shù);
2)當(dāng)需要獲取已讀、未讀人員列表時(shí),直接返回unread_list和read_list。
那么,思路2每條消息的存儲(chǔ)空間是:
未讀人員ID + 已讀人員ID,合計(jì)640個(gè)ID
思路2的實(shí)現(xiàn),占用的空間是案1的0.5倍~1.0倍。即案2占用的空間少,但在每次收到客戶(hù)端的已讀通知時(shí),比案1多了一個(gè)操作:從unread_list進(jìn)行減員。
5.4 存儲(chǔ)思路3(我的實(shí)現(xiàn))
5.4.1)探討5.2節(jié)、5.3節(jié)的不足:
5.2節(jié)、5.3節(jié)這兩種思路,都能滿(mǎn)足功能需求,但存在巨大的存儲(chǔ)浪費(fèi)。
該群有640人,如果群內(nèi)聊天每天有1024條消息,人員ID以4字節(jié)存儲(chǔ)計(jì)算,那么為該群每天的消息閱讀狀態(tài)需要消耗的空間是:
5.2節(jié)思路1:1024 * (640 * 4 + 已讀人數(shù) * 4),范圍是 2.5MB ~ 5MB;
5.3節(jié)思路2:1024 * 640 * 4,等于2.5MB。
這僅僅是一個(gè)群在一天之內(nèi)產(chǎn)生的閱讀狀態(tài)數(shù)據(jù),如果是在云平臺(tái)運(yùn)行,單此功能消耗的空間,呵呵~~
題外話(huà):如果成員不是用4字節(jié)整型存儲(chǔ),而改用字符串,比如"1123356777",那就更可觀(guān)了。
5.4.2)如何減少存儲(chǔ)空間:
考慮群成員并非時(shí)時(shí)刻刻都在變化,多數(shù)情況下,群成員的列表是相對(duì)穩(wěn)定的,今天的和上周(甚至更久以前)的列表甚至可能是一樣的,那么有可能幾百條消息,甚至幾萬(wàn)條消息對(duì)應(yīng)的群成員列表是相同的。
因此,引出本文的重點(diǎn)思想:
考慮讓不同的消息共用群成員列表,即把消息的閱讀狀態(tài)與群成員列表分開(kāi)存儲(chǔ),并記錄它們之間的關(guān)聯(lián)。
假定平均每1024條消息共用一個(gè)群成員列表,發(fā)了1024條消息后,群成員變化了,此后需要用新的群成員列表。
那么這一千條消息的閱讀狀態(tài)所占用的空間是:
群成員列表空間 + 1024條消息的閱讀狀態(tài):640 * 4 + 1024 * 每條消息的閱讀狀態(tài)所占空間
在具備群成員列表的前提下,如何減少每條消息的閱讀狀態(tài)所占空間?
很自然會(huì)想到用bit來(lái)表示已讀人員,因?yàn)橐粋€(gè)32位整型可表示32個(gè)人的已讀狀態(tài)。bit的順序只需與群成員列表的順序一致即可。
當(dāng)一條消息沒(méi)有人已讀時(shí),閱讀狀態(tài)占用0字節(jié);當(dāng)群內(nèi)每個(gè)人都閱讀時(shí),占用的空間最大,即640 / 32 = 20字節(jié)。
因此優(yōu)化之后,這一千條消息的閱讀狀態(tài)所占用的空間,范圍是2.5KB ~ (2.5KB + 1024 * 20B),即2.5KB ~ 22.5KB,此數(shù)值與5.2節(jié)思路1、5.3節(jié)思路2對(duì)比,有了極大幅度地下降。
如下圖所示:
該表格的前提條件:
1)一個(gè)群有640人;
2)該群連續(xù)1024條消息對(duì)應(yīng)的群成員列表是穩(wěn)定的。
退一步考慮,哪怕這1024條消息對(duì)應(yīng)的群成員列表不穩(wěn)定,中間變化了10次,那么也僅會(huì)多出2.5KB * 10即25KB的存儲(chǔ)空間,與案1、案2相比仍然有極大優(yōu)勢(shì)。
6、如何提高已讀未讀狀態(tài)的處理速度
小寶往公司群發(fā)了一條消息我來(lái)給大家介紹一下新來(lái)的女同事,大家立即、馬上、瞬間、閃電般地查看消息,感覺(jué)遲1秒就會(huì)失去秒殺女神的機(jī)會(huì)一樣,意味著一瞬間會(huì)有N多條已讀通知發(fā)送到IMS。
對(duì)這些消息的處理流程是一樣的:
1)可合并這些操作以批量形式進(jìn)行存儲(chǔ)、轉(zhuǎn)發(fā);
2)由于存儲(chǔ)消息的閱讀狀態(tài)是一個(gè)設(shè)置bit的過(guò)程,所以不存在互斥的問(wèn)題,即使在分布式環(huán)境也可以放心操作;
3)消息對(duì)應(yīng)的成員列表信息可臨時(shí)緩存在內(nèi)存對(duì)象內(nèi),以減少查詢(xún)IO,提高效率。
附錄:更多IM群聊技術(shù)文章
《快速裂變:見(jiàn)證微信強(qiáng)大后臺(tái)架構(gòu)從0到1的演進(jìn)歷程(一)》
《如何保證IM實(shí)時(shí)消息的“時(shí)序性”與“一致性”?》
《IM單聊和群聊中的在線(xiàn)狀態(tài)同步應(yīng)該用“推”還是“拉”?》
《IM群聊消息如此復(fù)雜,如何保證不丟不重?》
《微信后臺(tái)團(tuán)隊(duì):微信后臺(tái)異步消息隊(duì)列的優(yōu)化升級(jí)實(shí)踐分享》
《移動(dòng)端IM中大規(guī)模群消息的推送如何保證效率、實(shí)時(shí)性?》
《現(xiàn)代IM系統(tǒng)中聊天消息的同步和存儲(chǔ)方案探討》
《關(guān)于IM即時(shí)通訊群聊消息的亂序問(wèn)題討論》
《IM群聊消息的已讀回執(zhí)功能該怎么實(shí)現(xiàn)?》
《IM群聊消息究竟是存1份(即擴(kuò)散讀)還是存多份(即擴(kuò)散寫(xiě))?》
《一套高可用、易伸縮、高并發(fā)的IM群聊、單聊架構(gòu)方案設(shè)計(jì)實(shí)踐》
《[技術(shù)腦洞] 如果把14億中國(guó)人拉到一個(gè)微信群里技術(shù)上能實(shí)現(xiàn)嗎?》
《IM群聊機(jī)制,除了循環(huán)去發(fā)消息還有什么方式?如何優(yōu)化?》
《網(wǎng)易云信技術(shù)分享:IM中的萬(wàn)人群聊技術(shù)方案實(shí)踐總結(jié)》
《阿里釘釘技術(shù)分享:企業(yè)級(jí)IM王者——釘釘在后端架構(gòu)上的過(guò)人之處》
《IM群聊消息的已讀未讀功能在存儲(chǔ)空間方面的實(shí)現(xiàn)思路探討》
>>更多同類(lèi)文章 ……
(本文同步發(fā)布于:http://www.52im.net/thread-3054-1-1.html)
總結(jié)
以上是生活随笔為你收集整理的IM群聊消息的已读未读功能在存储空间方面的实现思路探讨的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux安装ssh和开启 ssh服务(
- 下一篇: 查看Product table entr