<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

    本文編寫時引用了“聊聊IM系統的即時性和可靠性”一文的部分內容和圖片,感謝原作者。

    1、引言

    上一篇《零基礎IM開發入門(二):什么是IM系統的實時性?》講到了IM系統的“立足”之本——“實時性”這個技術特征,本篇主要講解IM系統中的“可靠性”這個話題,內容盡量做到只講原理不深入展開,避開深層次的技術性探討,確保通俗易懂。


    閱讀對象:本系列文章主要閱讀對象為零IM基礎的開發者或產品經理,目標是告訴你“IM系統是什么?”,盡量不深入探討具體的技術實現,確保通俗易懂,老少皆宜。

    如您想從技術維度系統學習IM技術并著手自已的IM開發(即解決“IM系統要怎么做?”這個疑問),請從此文開始:《新手入門一篇就夠:從零開發移動端IM》。

    學習交流:

    - 即時通訊/推送技術開發交流5群:215477170[推薦]

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

    - 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK

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

    2、系列文章

    零基礎IM開發入門(一):什么是IM系統?

    零基礎IM開發入門(二):什么是IM系統的實時性?

    零基礎IM開發入門(三):什么是IM系統的可靠性?》(* 本文

    零基礎IM開發入門(四):什么是IM系統的消息時序一致性?

    《零基礎IM開發入門(五):什么是IM系統的安全性? (稍后發布)》

    《零基礎IM開發入門(六):什么是IM系統的的心跳機制? (稍后發布)》

    《零基礎IM開發入門(七):如何理解并實現IM系統消息未讀數? (稍后發布)》

    《零基礎IM開發入門(八):如何理解并實現IM系統的多端消息漫游? (稍后發布)》

    3、正文概述

    一般來說,IM系統的消息“可靠性”,通常就是指聊天消息投遞的可靠性(準確的說,這個“消息”是廣義的,因為還存用戶看不見的各種指令,為了通俗,統稱“消息”)。

    從用戶行為來講,消息“可靠性”應該分為兩種類型:

    • 1)在線消息的可靠性:即發送消息時,接收方當前處于“在線”狀態;
    • 2)離線消息的可靠性:即發送消息時,接收方當前處于“離線”狀態。

    從具體的技術表現來講,消息“可靠性”包含兩層含義:

    • 1)消息不丟:這很直白,發出去的消息不能像進了黑洞一樣,一臉懵逼可不行;
    • 2)消息不重:這是丟消息的反面,消息重復了也不能容忍。

    對于“消息不丟”這個特征來說,細化下來,它又包含兩重含義:

    • 1)已明確被對方收到;
    • 2)已明確未被對方收到。

    是的,對于第1)重含義好理解,第2)重含義的意思是:當對方沒有成功收到時,你的im系統也必須要感知到,否則,它同樣屬于被“丟”范疇。

    總之,一個成型的im系統,必須包含這兩種消息“可靠性”邏輯,才能堪用,缺一不可。

    消息的可靠性(不丟失、不重復)無疑是IM系統的重要指標,也是IM系統實現中的難點之一。本文以下文字,將從在線消息的可靠性和離線消息的可靠性進行討論。

    4、典型的在線消息收發流程

    先看下面這張典型的im消息收發流程: 

    是的,這是一個典型的服務端中轉型IM架構。

    所謂“服務端中轉型IM架構”是指:一條消息從客戶端A發出后,需要先經過 IM 服務器來進行中轉,然后再由 IM 服務器推送給客戶端B,這種模式也是目前最常見的 IM 系統的消息分發架構。

    你可能會說,IM不可以是P2P模式的嗎?是的,目前來說主流IM基本都是服務器中轉這種方式,P2P模式在IM系統中用的很少。

    原因是以下兩個很明顯的弊端:

    • 1)P2P模式下,IM運營者很容易被用戶架空(無法監管到用戶行為,用戶涉黃了怕不怕?);
    • 2)P2P模式下,群聊這種業務形態,很難實現(我要在千人群中發消息給,不可能我自已來分發1000次吧)。

    話題有點跑偏,我們回到正題:在上面這張圖里,客戶A發送消息到服務端、服務端中轉消息給客戶B,假設這兩條數據鏈接中使用的通信協議是TCP,你認為在TCP所謂可靠傳輸協議加持下,真的能保證IM聊天消息的可靠性嗎?

    答案是否定的。我們繼續看下節。

    5、TCP并不能保證在線消息的“可靠性”

    接上節,在一個典型的服務端中轉型IM架構中,即使使用“可靠的傳輸協議”TCP,也不能保證聊天消息的可靠性。為什么這么說?

    要回答這個問題,網上的很多文章,都會從服務端的角度舉例:比如消息發送時操作系統崩潰、網絡閃斷、存儲故障等等,總之很抽象,不太容易理解。

    這次我們從客戶端角度來理解,為什么使用了可靠傳輸協議TCP的情況下IM聊天消息仍然不可靠的問題。

    具體來說:如何確保 IM 消息的可靠性是個相對復雜的話題,從客戶端發送數據到服務器,再從服務器送達目標客戶端,最終在 UI 成功展示,其間涉及的環節很多,這里只取其中一環「接收端如何確保消息不丟失」來探討,粗略聊下我接觸過的兩種設計思路。

    說到可靠送達:第一反應會聯想到 TCP 的可靠性。數據的可靠送達是個通用性的問題,無論是網絡二進制流數據,還是上層的業務數據,都有可靠性保障問題,TCP 作為網絡基礎設施協議,其可靠性設計的可靠性是毋庸置疑的,我們就從 TCP 的可靠性說起。

    在 TCP 這一層:所有 Sender 發送的數據,每一個 byte 都有標號(Sequence Number),每個 byte 在抵達接收端之后都會被接收端返回一個確認信息(Ack Number), 二者關系為 Ack = Seq + 1。簡單來說,如果 Sender 發送一個 Seq = 1,長度為 100 bytes 的包,那么 receiver 會返回一個 Ack = 101 的包,如果 Sender 收到了這個Ack 包,說明數據確實被 Receiver 收到了,否則 Sender 會采取某種策略重發上面的包。

    第一個問題是:既然 TCP 本身是具備可靠性的,為什么還會出現消息接收端(Receiver)丟失消息的情況?

    看下圖一目了然:

    ▲ 上圖引用自《從客戶端的角度來談談移動端IM的消息可靠性和送達機制

    一句話總結上圖的含義:網絡層的可靠性不等同于業務層的可靠性。

    數據可靠抵達網絡層之后,還需要一層層往上移交處理,可能的處理有:

    • 1)安全性校驗;
    • 2)binary 解析;
    • 3)model 創建;
    • 4)寫 db;
    • 5)存入 cache;
    • 6)UI 展示;
    • 7)以及一些邊界問題:比如斷網、用戶突然退出登陸、磁盤已滿、內存溢出、app奔潰、突然關機等等。

    項目的功能特性越多,網絡層往上的處理出錯的可能性就越大。

    舉個最簡單的場景為例子:消息可靠抵達網絡層之后,寫 db 之前 IM APP 崩潰(不稀奇,是 App 都有崩潰的可能),雖然數據在網絡層可靠抵達了,但沒存進 db,下次用戶打開 App 消息自然就丟失了,如果不在業務層再增加可靠性保障(比如:后面要提到的網絡層面的消息重發保障),那么意味著這條消息對于接收端來說就永遠丟失了,也就自然不存在“可靠性”了。

    從客戶端角度理解IM的可能性以及解決辦法,可以詳細閱讀:從客戶端的角度來談談移動端IM的消息可靠性和送達機制》,本節引用的是該文中“4、TCP協議的可靠性之外還會出現消息丟失?”一節的文字。

    6、為在線消息增加“可靠性”保障

    那么怎樣在應用層增加可靠性保障呢?

    有一個現成的機制可供我們借鑒:TCP協議的超時、重傳、確認機制。

    具體來說就是:

    • 1)在應用層構造一種ACK消息,當接收方正確處理完消息后,向發送方發送ACK;
    • 2)假如發送方在超時時間內沒有收到ACK,則認為消息發送失敗,需要進行重傳或其他處理。

    增加了確認機制的消息收發過程如下: 

    我們可以把整個過程分為兩個階段。

    階段1:clientA -> server

    • 1-1:clientA向server發送消息(msg-Req);
    • 1-2:server收取消息,回復ACK(msg-Ack)給clientA;
    • 1-3:一旦clientA收到ACK即可認為消息已成功投遞,第一階段結束。

    無論msg-A或ack-A丟失,clientA均無法在超時時間內收到ACK,此時可以提示用戶發送失敗,手動進行重發。

    階段2:server -> clientB

    • 2-1:server向clientB發送消息(Notify-Req);
    • 2-2:clientB收取消息,回復ACK(Notify-ACk)給server;
    • 2-3:server收到ACK之后將該消息標記為已發送,第二階段結束。

    無論msg-B或ack-B丟失,server均無法在超時時間內收到ACK,此時需要重發msg-B,直到clientB返回ACK為止。

    關于IM聊天消息的可靠性保障問的深入討論,可以詳讀:IM消息送達保證機制實現(一):保證在線實時消息的可靠投遞》,該文會深入討論這個話題。

    7、典型的離線消息收發流程

    說完在線消息的“可靠性”問題,我們該了解一下離線消息了。

    7.1 離線消息的收發也存在“不可靠性”

    下圖是一張典型的IM離線消息流程圖:

    如上圖所示,和在線消息收發流程類似。

    離線消息收發流程也可劃分為兩個階段:

    階段1:clientA -> server

    • 1-1:clientA向server發送消息(msg-Req) ;
    • 1-2:server發現clientB離線,將消息存入offline-DB。

    階段2:server -> clientB

    • 2-1:clientB上線后向server拉取離線消息(pull-Req) ;
    • 2-2:server從offline-DB檢索相應的離線消息推送給clientB(pull-res),并從offline-DB中刪除。

    顯然:離線消息收發過程同樣存在消息丟失的可能性。

    舉例來說:假設pull-res沒有成功送達clientB,而offline-DB中已刪除,這部分離線消息就徹底丟失了。

    7.2 離線消息的“可靠性”保障

    與在線消息收發流程類似,我們同樣需要在應用層增加可靠性保障機制。

    下圖是增加了可靠性保障后的離線消息收發流程: 

    與初始的離線消息收發流程相比,上圖增加了1-3、2-4、2-5步驟:

    • 1-3:server將消息存入offline-DB后,回復ACK(msg-Ack)給clientA,clientA收到ACK即可認為消息投遞成功;
    • 2-4:clientB收到推送的離線消息,回復ACK(res-Ack)給server;
    • 2-5:server收到res-ACk后確定離線消息已被clientB成功收取,此時才能從offline-DB中刪除。

    當然,上述的保障機制,還存在性能優化空間。

    當離線消息的量較大時:如果對每條消息都回復ACK,無疑會大大增加客戶端與服務器的通信次數。這種情況我們通常使用批量ACK的方式,對多條消息僅回復一個ACK。在某此后IM的實現中是將所有的離線消息按會話進行分組,每組回復一個ACK,假如某個ACK丟失,則只需要重傳該會話的所有離線消息。

    有關離線消息的可靠性保障機制的詳細討論,可以詳讀:IM消息送達保證機制實現(二):保證離線消息的可靠投遞》、《IM開發干貨分享:如何優雅的實現大量離線消息的可靠投遞》,這兩篇文章可以給你更深入具體的答案。

    8、聊天消息重復的問題

    上面章節中,通過在應用層加入重傳、確認機制后,我們確實是杜絕了消息丟失的可能性。

    但由于重試機制的存在,我們會遇到一個新的問題:那就是同一條消息可能被重復發送。

    舉一個最簡單的例子:假設client成功收到了server推送的消息,但其后續發送的ACK丟失了,那么server將會在超時后再次推送該消息,如果業務層不對重復消息進行處理,那么用戶就會看到兩條完全一樣的消息。

    消息去重的方式其實非常簡單,一般是根據消息的唯一標志(id)進行過濾。

    具體過程在服務端和客戶端可能有所不同:

    • 1)客戶端 :我們可以通過構造一個map來維護已接收消息的id,當收到id重復的消息時直接丟棄;
    • 2)服務端 :收到消息時根據id去數據庫查詢,若庫中已存在則不進行處理,但仍然需要向客戶端回復Ack(因為這條消息很可能來自用戶的手動重發)。

    關于消息的去重問題,在一對一聊天的情況下,邏輯并不復雜,但在群聊模式下,會將問題復雜化,有關群聊消息不丟和去重的詳細討論,可以深入閱讀:《IM群聊消息如此復雜,如何保證不丟不重?》。

    9、本文小結

    保證消息的可靠性是IM系統設計中很重要的一環,能不能做到“消息不丟”、“消息不重”,對用戶的體驗影響極大。

    所謂“可靠的傳輸協議”TCP也并不能保障消息在應用層的可靠性。

    我們一般通過在應用層的ACK應答和重傳機制,來實現IM消息的可靠性保障。但由此帶來的消息重復問題,需要我們額外進行處理,最簡單的方法就是通過消息ID進行冪等去重。

    關于IM系統消息可靠性的理論基礎,我們就探討到這里,有疑問的讀者,可以在本文末尾留意,歡迎積極討論。

    10、參考資料

    [1] IM消息送達保證機制實現(一):保證在線實時消息的可靠投遞

    [2] IM消息送達保證機制實現(二):保證離線消息的可靠投遞

    [3] IM開發干貨分享:如何優雅的實現大量離線消息的可靠投遞

    [4] 從客戶端的角度來談談移動端IM的消息可靠性和送達機制

    [5] 聊聊IM系統的即時性和可靠性

    [6] 學習筆記4——IM系統如何保證消息的可靠性

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

    附錄:更多IM開發熱門技術點

    移動端IM開發者必讀(一):通俗易懂,理解移動網絡的“弱”和“慢”

    移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結

    現代移動端網絡短連接的優化手段總結:請求速度、弱網適應、安全保障

    移動端IM中大規模群消息的推送如何保證效率、實時性?

    移動端IM開發需要面對的技術問題

    開發IM是自己設計協議用字節流好還是字符流好?

    請問有人知道語音留言聊天的主流實現方式嗎?

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

    一個低成本確保IM消息時序的方法探討

    IM單聊和群聊中的在線狀態同步應該用“推”還是“拉”?

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

    談談移動端 IM 開發中登錄請求的優化

    移動端IM登錄時拉取數據如何作到省流量?

    淺談移動端IM的多點登錄和消息漫游原理

    完全自已開發的IM該如何設計“失敗重試”機制?

    微信對網絡影響的技術試驗及分析(論文全文)

    IM開發基礎知識補課(五):通俗易懂,正確理解并用好MQ消息隊列

    微信技術分享:微信的海量IM聊天消息序列號生成實踐(算法原理篇)

    IM開發基礎知識補課(六):數據庫用NoSQL還是SQL?讀這篇就夠了!

    IM里“附近的人”功能實現原理是什么?如何高效率地實現它?

    IM的掃碼登錄功能如何實現?一文搞懂主流應用的掃碼登錄技術原理

    IM消息ID技術專題(一):微信的海量IM聊天消息序列號生成實踐(算法原理篇)

    IM消息ID技術專題(二):微信的海量IM聊天消息序列號生成實踐(容災方案篇)

    IM消息ID技術專題(三):解密融云IM產品的聊天消息ID生成策略

    IM消息ID技術專題(四):深度解密美團的分布式ID生成算法

    IM消息ID技術專題(五):開源分布式ID生成器UidGenerator的技術實現

    IM消息ID技術專題(六):深度解密滴滴的高性能ID生成器(Tinyid)

    IM開發寶典:史上最全,微信各種功能參數和邏輯規則資料匯總

    本文已同步發布于“即時通訊技術圈”公眾號。

    ▲ 本文在公眾號上的鏈接是:點此進入,原文鏈接是:http://www.52im.net/thread-3182-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
    主站蜘蛛池模板: 亚洲日韩人妻第一页| 97精品免费视频| 人禽伦免费交视频播放| 亚洲aⅴ无码专区在线观看 | 亚洲毛片免费观看| 中文字幕免费视频一| 99久久久国产精品免费牛牛 | 国产午夜亚洲精品不卡免下载| 亚洲中文字幕乱码AV波多JI| 亚洲熟妇无码八V在线播放| 久久综合久久综合亚洲| 亚洲欧美日韩中文二区| 亚洲国产AV一区二区三区四区| www亚洲精品久久久乳| 青青草97国产精品免费观看| 免费很黄无遮挡的视频毛片| 人妻免费久久久久久久了| 一区在线免费观看| 精品免费视在线观看| 91人成网站色www免费下载| jjizz全部免费看片| 女人与禽交视频免费看| 国产精品免费播放| 久久亚洲av无码精品浪潮| 亚洲成AV人片在线播放无码| 亚洲专区先锋影音| 亚洲kkk4444在线观看| 亚洲AV成人片无码网站| v片免费在线观看| 久久精品电影免费动漫| 91香蕉成人免费网站| 国外成人免费高清激情视频| 亚洲成年看片在线观看| 国产亚洲精品a在线无码| 亚洲精品国产电影午夜| 亚洲av无码日韩av无码网站冲| yellow视频免费在线观看| 无码日韩精品一区二区免费暖暖| 无码中文字幕av免费放| 亚洲国产一区视频| 老汉色老汉首页a亚洲|