Home / ?????? ????? ??????????? ???? / 龍笛特色 / 從客戶端的角度來談?wù)勔苿?dòng)端IM的消息可靠性和送達(dá)機(jī)制

從客戶端的角度來談?wù)勔苿?dòng)端IM的消息可靠性和送達(dá)機(jī)制

IM App 是我做過 App 類型里復(fù)雜度最高的一類,里面可供深究探討的技術(shù)難點(diǎn)非常之多。這篇文章和大家聊下從移動(dòng)端客戶端的角度所關(guān)注的IM消息可靠性和送達(dá)機(jī)制(因?yàn)槲覀€(gè)人對(duì)移動(dòng)客戶端的經(jīng)驗(yàn)積累的比較豐富嘛)。

TCP協(xié)議的可靠性之外還會(huì)出現(xiàn)消息丟失?

如何確保 IM 不丟消息是個(gè)相對(duì)復(fù)雜的話題,從客戶端發(fā)送數(shù)據(jù)到服務(wù)器,再從服務(wù)器抵達(dá)目標(biāo)客戶端,最終在 UI 成功展示,其間涉及的環(huán)節(jié)很多,這里只取其中一環(huán)「接收端如何確保消息不丟失」來探討,粗略聊下我接觸過的兩種設(shè)計(jì)思路。

說到可靠抵達(dá),第一反應(yīng)會(huì)聯(lián)想到 TCP 的 reliability。數(shù)據(jù)可靠抵達(dá)是個(gè)通用性的問題,無論是網(wǎng)絡(luò)二進(jìn)制流數(shù)據(jù),還是上層的業(yè)務(wù)數(shù)據(jù),都有可靠性保障問題,TCP 作為網(wǎng)絡(luò)基礎(chǔ)設(shè)施協(xié)議,其可靠性設(shè)計(jì)的可靠性是毋庸置疑的,我們就從 TCP 的可靠性說起。

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

第一個(gè)問題是:現(xiàn)在的 IM App 幾乎都是走 TCP 通道,既然 TCP 本身是具備可靠性的,為什么還會(huì)出現(xiàn)消息接收端(Receiver)丟失消息的情況,看下圖一目了然:

一句話總結(jié)上圖的含義:網(wǎng)絡(luò)層的可靠性不等同于業(yè)務(wù)層的可靠性。

數(shù)據(jù)可靠抵達(dá)網(wǎng)絡(luò)層之后,還需要一層層往上移交處理,可能的處理有:安全性校驗(yàn),binary 解析,model 創(chuàng)建,寫 db,存入 cache,UI 展示,以及一些 edge cases(斷網(wǎng),用戶 logout,disk full,OOM,crash,關(guān)機(jī)。。) 等等,項(xiàng)目的 feature 越多,網(wǎng)絡(luò)層往上的處理出錯(cuò)的可能性就越大。

舉個(gè)最簡單的場景為例子:消息可靠抵達(dá)網(wǎng)絡(luò)層之后,寫 db 之前 App crash(不稀奇,是 App 都會(huì) crash),雖然數(shù)據(jù)在網(wǎng)絡(luò)層可靠抵達(dá)了,但沒存進(jìn) db,下次用戶打開 App 消息自然就丟失了,如果不在業(yè)務(wù)層再增加可靠性保障,網(wǎng)絡(luò)層面不會(huì)重發(fā),那么意味著這條消息對(duì)于 Receiver 永遠(yuǎn)丟失了。

客戶端方案1:應(yīng)用層 Ack 消息

這個(gè)方案可以簡單理解為,將 TCP 的 Ack 流程再走一遍,在應(yīng)用層也構(gòu)建一個(gè) Ack 消息,在應(yīng)用層可靠性得到確認(rèn)(一般以存入 db 為準(zhǔn),更準(zhǔn)確說是事務(wù)提交成功的回調(diào)函數(shù))之后再發(fā)送這個(gè) Ack 消息,Server 收到應(yīng)用層 Ack 消息之后才認(rèn)為 Receiver 已收到,否則也采取某種策略重發(fā)消息。

具體到 IM App 當(dāng)中,接收端接受到 Server 的 Message,將 Message 存入 db,在確認(rèn)回調(diào)里發(fā)送 Ack Receive 消息,Server 收到 Ack Receive 即認(rèn)為消息已經(jīng)可靠抵達(dá),否則會(huì)在某個(gè)時(shí)機(jī)重新推送(比如客戶端重連服務(wù)器時(shí)候 Pull,比如有新消息時(shí) Server Push)。

客戶端方案2:應(yīng)用層 Seq ID

這個(gè)方案和上面不同,但也是在應(yīng)用層操作。我們個(gè)每個(gè) Message 分配一個(gè) Seq ID,這個(gè) Seq ID 對(duì)于單個(gè)用戶的接受消息隊(duì)列來說是連續(xù)的,如果 Message A 和 Message B 是相鄰的,那么 MsgBSeqID = MsgASeqID + 1。每次存入 db 的時(shí)候更新 db 里的 LastReceivedSeqID,LastReceivedSeqID 即為上一條寫入數(shù)據(jù)庫消息的 Seq ID。

這么做的好處是,每次從網(wǎng)絡(luò)層收到消息時(shí),從 db 里取出 LastReceivedSeqID,如果 LastReceivedSeqID = 新消息 Seq ID - 1,那么說明應(yīng)用層消息時(shí)連續(xù)的沒有發(fā)生丟失。還可以對(duì)收到的批量消息做預(yù)檢測(cè),檢查消息隊(duì)列里的 Seq ID 是否為聯(lián)系的,只要存在任何一種不連續(xù)的 Seq ID 情況,就說明發(fā)送了丟失,此時(shí)接收端可以用 LastReceivedSeqID 從 Server 重新獲取準(zhǔn)確的接受消息隊(duì)列。

這么做的好處是避免了每次都需要發(fā)送一條 Ack 消息,壞處是應(yīng)用層邏輯復(fù)雜之后,一旦出現(xiàn) Seq ID 不連續(xù)的情況,會(huì)過度依賴于 refetch,難以分析問題出現(xiàn)的原因,refetch 一旦過于頻繁,其流量損耗極有可能大于 Ack 消息的數(shù)據(jù)量。

本文小結(jié)

消息的可靠抵達(dá)可以抽象為更一般意義上的可靠性問題,工程上總會(huì)碰到需要解決各種形式可靠性問題的場景,以經(jīng)典計(jì)算機(jī)理論或者實(shí)踐為基礎(chǔ)來分析應(yīng)用層的工程問題,可以舉一反三,藥到病除。

在工程上實(shí)踐可靠性,需要線了解工程的每一個(gè)環(huán)節(jié)以及數(shù)據(jù)如何在各個(gè)環(huán)節(jié)流動(dòng),接下來才是分析每一個(gè)環(huán)節(jié)數(shù)據(jù)出錯(cuò)的可能性。檢驗(yàn)可靠性的標(biāo)準(zhǔn)時(shí)「入袋為安」,存入 db 或者以其他方式持久化到 disk 當(dāng)中,這樣才能保證客戶端每次都能正確讀取到消息。

另外,可靠性可以理解為兩方面:

· 一是數(shù)據(jù)可靠抵達(dá)(沒有任何中間數(shù)據(jù)被丟失);

· 二是正確抵達(dá)(沒有亂序或者數(shù)據(jù)更改)。

其實(shí)理論上 TCP 也不是 100% 可靠(數(shù)據(jù)有可能在傳輸時(shí)改變而無法被檢測(cè)到),而是 100% 工程上可靠(數(shù)據(jù)改變而不被檢測(cè)到時(shí)個(gè)極小概率的事件),這是另外一個(gè)有意思的話題。

中文字幕丰满乱孑伦无码专区| 日韩熟妇精品| 91精品国产91| A级全黄120分视频| 久久久久亚洲AV成人网人人软件| 日韩人妖无码区| 国产农村乱子伦精品视频| 午夜一级片在线看| 国产欧美日韩一区二区加勒比| AV日韩不卡了| 亚洲首页国产精品丝袜| 久久综合亚洲精品| 欧美色图中文字幕| 久久国产一区三| 婷婷电影房综合| 最新国产在线拍揄自揄视频| www久久一区二区| 熟妇人妻系列AV无码| 欧美日韩三级黄色| 国产亚洲另类精品| 四虎性无码性| 蜜桃 久久| 在线无码精品一区| 精品白桨系列,星座网| 国产无码精品一二三| 日本另类黄色网站| 粉嫩在线一区二区懂色| 国产精品久久久久AAAA| 日韩有码在线观看视频| 一区二区三区三区| 深夜国产91999| 久久久久久久午夜| 欧美一级特黄特黄大片连接| 精品国产免费网站入口| 精品人人莫久久| 久久久av| 久久精热96国产\| xxxxx18色| chese少妇hd| 与亲女洗澡伦了东北| 亚洲午夜福利无码|