<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

    本文引用了架構師之路公眾號作者沈劍的文章,內容有改動,感謝原作者。


    1、前言


    我們平時在使用即時通訊應用時候,每當發出一條聊天消息,都希望對方盡快看到,并盡快回復,但對方到底有沒有真的看到?我卻并不知道。

    一個殘酷的現實是,很多時候對方其實是早就已經看到了這條消息,但出出種種原因(大家都懂的),通常都是默默返回——假裝沒看見。

    像微信這樣的熟人社交工具,在產品的設計理念上,為了保持使用者的隱私性,在線狀態、已讀回執等涉及隱私的功能,都沒有提供。但很多時候,尤其商務、辦公場合下,特別需要一種強反饋的工具,這對于打造高效的團隊很有幫助(雖然員工很反感,但老板都喜歡這樣的功能,哈哈)。

    目前市面上主流的移動端IM里,提供了已讀回執的主要有阿里的釘釘、網易的易信、阿里的旺旺,如下圖所示:
    IM群聊消息的已讀回執功能該怎么實現?_22.jpg    IM群聊消息的已讀回執功能該怎么實現?_11.jpg    IM群聊消息的已讀回執功能該怎么實現?_33.jpg 
    ▲ 上圖從左至右分別為:釘釘、易信、旺旺(千牛)

    以阿里的釘釘為例,釘釘的產品定位是用于商務交流,其“強制已讀回執”功能,讓職場人無法再“假裝不在線”、“假裝沒收到”。更有甚者,釘釘的群聊“強制已讀回執”功能,甚至能夠知道誰讀了消息,誰沒有讀消息(老板的福音啊)

    那么群聊消息的收發流程、消息的送達保證、已讀回執機制,到底該怎么實現呢?這就是今天要討論的話題。

    學習交流:

    - 即時通訊開發交流3群:185926912[推薦]

    - 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM

    (本文同步發布于:http://www.52im.net/thread-1611-1-1.html

    2、IM開發干貨系列文章


    本文是系列文章中的第14篇,總目錄如下:


    另外,如果您是IM開發初學者,強烈建議首先閱讀《新手入門一篇就夠:從零開發移動端IM》。

    3、正文引言


    首先我們需要了解一下群消息的設計、投遞流程以及可達性保證機制,因不是本文要討論的重點,所以盡量言簡意賅,更詳細的資料請見下方的推薦文章列表。

    如您對聊天消息的投遞和送達機制等尚無概念,可先讀本系列文章的以下幾篇,有助于您詳細掌握這方面的內容:


    4、群消息怎么設計?


    大家一起跟著樓主的節奏,一步一步來看群消息怎么設計。

    核心問題1:群消息,只存一份?還是,每個成員存一份?
    答:存一份,為每個成員設置一個群消息隊列,會有大量數據冗余,并不合適。

    核心問題2:如果群消息只存一份,怎么知道每個成員讀了哪些消息?
    答:可以利用群消息的偏序關系,記錄每個成員的last_ack_msgid(last_ack_time),這條消息之前的消息已讀,這條消息之后的消息未讀。該方案意味著,對于群內的每一個用戶,只需要記錄一個值即可。

    解答上述兩個核心問題后,很容易得到群消息的核心數據結構。

    群消息表:記錄群消息

    group_msgs(msgid, gid, sender_uid, time, content);


    各字段的含義為:消息ID,群ID,發送方UID,發送時間,發送內容。

    群成員表:記錄群里的成員,以及每個成員收到的最后一條群消息

    group_users(gid, uid, last_ack_msgid);


    各字段的含義為:群ID,群成員UID,群成員最后收到的一條群消息ID。

    5、了解一下群消息發送的流程


    在核心數據結構設計完之后,一起來看看群消息發送的流程(本系列中的文章《IM群聊消息如此復雜,如何保證不丟不重?》詳細講解了這個過程,可以深入讀一讀)。

    業務場景:

    • 1)一個群中有A, uid1, uid2, uid3四名成員;
    • 2)A, uid1, uid2在線,期望實時收到在線消息;
    • 3)uid3離線,期望未來拉取到離線消息。

    IM群聊消息的已讀回執功能該怎么實現?_1.jpg 

    其整個消息發送的流程1-4如上圖:

    • 1)A發出群消息;
    • 2)server收到消息后,一來要將群消息落地,二來要查詢群里有哪些群成員,以便實施推送;
    • 3)對于群成員,查詢在線狀態;
    • 4)對于在線的群成員,實施推送。

    這個流程里,只要第二步消息落地完成,就能保證群消息不會丟失

    核心問題3:如何保證接收方一定收到群消息?
    答:各個收到消息后,要修改各群成員的last_ack_msgid,以告訴系統,這一條消息確認收到了。

    在線消息,離線消息的last_ack_msgid的修改,又各有不同。

    IM群聊消息的已讀回執功能該怎么實現?_2.jpg 
    對于在線的群友,收到群消息后,第一時間會ack、修改last_ack_msgid

    IM群聊消息的已讀回執功能該怎么實現?_3.jpg 
    對于離線的群友,會在下一次登錄時,拉取未讀的所有群離線消息,并將last_ack_msgid修改為最新的一條消息

    核心問題4:如果ack丟失,群友會不會拉取重復的群消息?
    答:,可以根據msgid在客戶端本地做去重,即使系統層面收到了重復的消息,仍然可以保證良好的用戶體驗。

    上述流程,只能確保接收方收到消息,發送方仍然不知道哪些人在線閱讀了消息,哪些人離線未閱讀消息,并沒有實現已讀回執,那已讀回執會對系統設計產生什么樣的影響呢?

    6、已讀回執流程的設計


    前面的基礎知識我們已經了解的差不多,本節來討論本文的重點內容,即群聊已讀回執流程到底該怎么設計。

    對于發送方發送的任何一條群消息,都需要知道,這條消息有多少人已讀多少人未讀,就需要一個基礎表來記錄這個關系

    消息回執表:用來記錄消息的已讀回執

    msg_acks(sender_uid, msgid, recv_uid, gid,if_ack);


    各字段的含義為:發送方UID,消息ID,回執方UID,群ID,回執標記。

    增加了已讀回執邏輯后,群消息的流程會有細微的改變,見下圖:
    IM群聊消息的已讀回執功能該怎么實現?_4.jpg 

    接著,server收到消息后,除了要:

    • 1)將群消息落地;
    • 2)查詢群里有哪些群成員,以便實施推送;

    之外,還需要:

    • 3)插入每條消息的初始回執狀態。

    IM群聊消息的已讀回執功能該怎么實現?_5.jpg 

    接收方修改last_ack_msgid的流程,會變為:

    • 1)發送ack請求;
    • 2)修改last_ack_msgid,并且,修改已讀回執if_ack狀態;
    • 3)查詢發送方在線狀態;
    • 4)向發送方實時推送已讀回執(如果發送方在線);

    如果發送方不在線,ta會在下次登錄的時候:

    • 5)從關聯表里拉取每條消息的已讀回執。

    這里的初步結論是:

    • 如果發送方在線:會實時被推送已讀回執;
    • 如果發送方不在線:會在下次在線時拉取已讀回執。

    7、已讀回執流程優化方案


    再次詳細的分析下,群消息已讀回執的“消息風暴擴散系數”,假設每個群有200個用戶,其中20%的用戶在線,即40各用戶在線。

    那么,群用戶每發送一條群消息,會有:

    • 40個消息,通知給群友;
    • 40個ack修改last_ack_msgid,發給服務端;
    • 40個已讀回執,通知給發送方。

    可見,其消息風暴擴散系數非常之大

    同時:

    • 需要存儲40條ack記錄。

    群數量,群友數量,群消息數量越來越多之后,存儲也會成為問題

    是否有優化方案呢?

    群消息的推送,能否改為接收方輪詢拉取?
    答:不能,消息接收,實時性是核心指標。

    對于last_ack_msgid的修改,真的需要每個群消息都進行ack么?
    答:其實不需要,可以批量ack,累計收到N條群消息(例如10條),再向服務器發送一次last_ack_msgid的修改請求,同時修改這個請求之前所有請求的已讀回執,這樣就能將40個發送給服務端的ack請求量,降為原來的1/10。

    會帶來什么副作用?
    答:last_ack_msgid的作用是,記錄接收方最近新取的一條群消息,如果不實時更新,可能導致,異常退出時,有一些群消息沒來得及更新last_ack_msgid,使得下次登陸時,會拉取到重復的群消息。但這不是問題,客戶端可以根據msgid去重,用戶體驗不會受影響

    發送方在線時,對于已讀回執的發送,真的需要實時推送么?
    答:其實不需要,發送方每發一條消息,會收到40個已讀回執,采用輪詢拉取(例如1分鐘一次,一個小時也就60個請求),可以大大降低請求量。
    畫外音:或者直接放到應用層keepalive請求里,做到0額外請求增加。

    會帶來什么副作用?
    答:已讀回執更新不實時,最壞的情況下,1分鐘才更新回執。當然,可以根據性能與產品體驗來折衷配置這個輪詢時間。

    如何降低數據量?
    答:回執數據不是核心數據
    • 已讀的消息,可以進行物理刪除,而不是標記刪除;
    • 超過N長時間的回執,歸檔或者刪除掉。

    8、本文小結


    對于群消息已讀回執,一般來說:

    • 如果發送方在線,會實時被推送已讀回執;
    • 如果發送方不在線,會在下次在線時拉取已讀回執。

    如果要對進行優化,可以:

    • 接收方累計收到N條群消息再批量ack;
    • 發送方輪詢拉取已讀回執。

    物理刪除已讀回執數據,定時刪除或歸檔非核心歷史數據。

    (本文同步發布于:http://www.52im.net/thread-1611-1-1.html

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


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


    網站導航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: 青青草a免费线观a| 四虎精品视频在线永久免费观看| 四虎成人免费影院网址| 亚洲人成影院77777| 西西大胆无码视频免费| 亚洲中文字幕精品久久| 免费无码看av的网站| 国产成人va亚洲电影| 亚洲精品无码专区久久同性男| 亚洲视频在线免费| 亚洲av午夜成人片精品网站| 全部免费毛片在线播放| 亚洲婷婷天堂在线综合| 成人毛片免费在线观看| 老司机午夜精品视频在线观看免费 | 国产亚洲精品2021自在线| 亚洲国产成人久久笫一页| 国产黄在线播放免费观看| 国产亚洲精品激情都市| 久久99青青精品免费观看| 亚洲一区二区三区亚瑟| 免费日本黄色网址| baoyu777永久免费视频 | 国产亚洲男人的天堂在线观看| 99麻豆久久久国产精品免费| 最近中文字幕完整版免费高清 | 亚洲熟妇无码八AV在线播放| 男女午夜24式免费视频| 亚洲日韩乱码中文无码蜜桃 | 立即播放免费毛片一级| 中文字幕亚洲不卡在线亚瑟| 久久久99精品免费观看| 亚洲熟妇AV日韩熟妇在线| 亚洲午夜无码AV毛片久久| 亚在线观看免费视频入口| 国产亚洲精aa在线看| 国产AV无码专区亚洲AV漫画 | 美女无遮挡拍拍拍免费视频| 免费日本一区二区| 免费永久看黄在线观看app| 色www永久免费网站|