消息推和拉的區(qū)別

對于一個可靠的IM系統(tǒng)戴陡,需要保證消息的百分之百到達(dá)對端塞绿。即使是在極端情況下丟失一條消息也是不能容忍的。一個極其極其低概率的事件恤批,若是放大到分布式系統(tǒng)中异吻,那這個概率事件就成了必然事件。在開發(fā)測試中如果發(fā)現(xiàn)一次偶然的消息丟失問題而忽略不查喜庞,那上線之后就必然會發(fā)生消息丟失诀浪。所以作為技術(shù),一定不能放過任何一個極端情況下發(fā)生的問題延都。

在服務(wù)器給客戶端發(fā)送消息的過程中雷猪,有兩種方式,1.主動推送消息給客戶端晰房;2.客戶端來拉消息求摇。這兩種方式都可以達(dá)到目的,下面就來分析一下兩者的區(qū)別殊者。

A ? -> ?SERVER ?-> B

上述描述一種簡單模型与境,A給B發(fā)送一條消息,首先會到達(dá)服務(wù)器猖吴,然后服務(wù)器將消息轉(zhuǎn)發(fā)給客戶端B摔刁。這是推的方式,服務(wù)器是直接將消息推給客戶端的海蔽。那在復(fù)雜的網(wǎng)絡(luò)環(huán)境中共屈,如何保證消息能夠到達(dá)B端?

這個例子有兩處需要做保證准潭,第一是如何保證A發(fā)出去的消息成功到達(dá)服務(wù)器趁俊。第二處是服務(wù)器推給B的消息如何知道已經(jīng)成功送達(dá)。

本文主要分析第二條刑然。

在正常情況下,服務(wù)器直接把消息下發(fā)給B端就完事了暇务,這也是大家最希望看到的結(jié)果泼掠。如果僅僅這樣處理,那系統(tǒng)會常常因為這個環(huán)節(jié)丟消息垦细,而且非常嚴(yán)重择镇。我們需要考慮以下幾種情況。第一括改,對方不在線怎么辦腻豌。第二,在移動網(wǎng)絡(luò)下,信號經(jīng)常會不穩(wěn)定吝梅,比如乘坐地鐵過隧道虱疏,信號會中斷,會導(dǎo)致消息沒有成功到達(dá)對端苏携。如何保證消息可靠抵達(dá)做瞪?

1.當(dāng)知道對端不在線的情況下,將消息存在服務(wù)器右冻,等待客戶端下次登陸來拉取装蓬。

2.對于沒推成功的情況,服務(wù)器增加重推的機(jī)制纱扭,客戶端收到消息后給服務(wù)器回復(fù)確認(rèn)牍帚,服務(wù)器取消后續(xù)推送。

新增的邏輯引入新的復(fù)雜度乳蛾,需要解決暗赶。

1.要確保成功將消息存儲在服務(wù)器,如果存儲失敗屡久,算是丟失消息忆首。這樣就要對存儲失敗的情況做檢測。一種是明確知道存失敗了被环,另一種是后端服務(wù)超時糙及,不知道有沒有存成功。存儲失敗可以重試筛欢,存儲超時也可以簡單認(rèn)為是存儲失敗浸锨,再重試。只要保證多次存儲同一消息是冪等操作就可以版姑,防止存了兩條柱搜。

2.對于重推,服務(wù)器要實現(xiàn)重推邏輯剥险,把推送操作加到定時器里面聪蘸,同時緩存這條消息。超時未收到客戶端的確認(rèn)就再推一次表制。由于網(wǎng)絡(luò)原因或者客戶端卡住健爬,會導(dǎo)致推送的消息到達(dá)了客戶端,但是客戶端的確認(rèn)一直沒有到達(dá)服務(wù)器么介,導(dǎo)致服務(wù)器推送了多次消息娜遵,所以客戶端需要對消息做重復(fù)消息的過濾。其次是多次推送后壤短,客戶端一直沒有回復(fù)確認(rèn)设拟,這個可能是網(wǎng)絡(luò)原因慨仿,客戶端真沒收到,也可能客戶端收到了纳胧,客戶端的確認(rèn)還在路上镰吆,但是已經(jīng)到了服務(wù)器重推次數(shù),服務(wù)器決定要不要將消息存儲到服務(wù)器躲雅?鑒于客戶端實現(xiàn)了消息過濾機(jī)制鼎姊,此處可以簡單地存儲消息到服務(wù)器。這就走1的邏輯相赁。后續(xù)客戶端再上線時拉服務(wù)端存儲的消息相寇,并做重復(fù)過濾。能保證消息不丟失钮科。

3.既然會拉取之前存儲在服務(wù)器的消息唤衫,那拉取完成之后需要將服務(wù)器存儲的消息刪除,這一步客戶端在確認(rèn)收到消息后再發(fā)刪除請求即可绵脯。否則每次都會拉一遍佳励,耗費(fèi)流量,而且消息多了會導(dǎo)致登陸后的收消息流程越來越卡蛆挫,由于有過濾機(jī)制赃承,不會出現(xiàn)重復(fù)消息顯示。

上述是推的方式實現(xiàn)消息可靠送達(dá)的復(fù)雜度悴侵。之間還有些邏輯沒包含進(jìn)來瞧剖,比如push】擅猓客戶端沒收到消息應(yīng)該改推push抓于。那這樣一來推push的情況就有很多。公司之前的老系統(tǒng)是采用推的方式浇借,我們在這一塊踩過很多坑捉撮,服務(wù)端的實現(xiàn)邏輯也相當(dāng)復(fù)雜,各種判斷妇垢,包括存消息到服務(wù)器巾遭,重推消息給客戶端,推push給客戶端闯估,考慮多設(shè)備問題恢总,根據(jù)客戶端的確認(rèn)做重推取消等等。個人看法是:相信我睬愤,如果這樣做,后果很嚴(yán)重纹安,你會因頻繁的消息丟失問題沉浸在復(fù)雜的代碼邏輯中無法自拔尤辱,甚至砂豌,開始懷疑人生。

接下來分析下拉消息的實現(xiàn)方式光督。

A ?-> SERVER -> ?B

B <--> SERVER

如果說推的方式是一步到位阳距,那拉消息的實現(xiàn)方式分為兩步。第一结借,A將消息發(fā)送到服務(wù)器筐摘,服務(wù)器存儲這條消息,并發(fā)送一個通知給客戶端B船老,告訴他有消息來了咖熟,快來拉取。第二柳畔,客戶端來拉取這條消息馍管,收到后刪除服務(wù)器的這條消息。同樣的問題薪韩,有兩點(diǎn)需要注意确沸。第一,網(wǎng)絡(luò)原因?qū)е峦ㄖ獩]到對端俘陷,第二罗捎,對方不在線怎么辦?如何保證消息可靠抵達(dá)拉盾?

拉的方式下桨菜,可以先將消息存儲到服務(wù)器,再來給發(fā)送者和接收者推通知盾剩。如果消息存儲失敗雷激,就可以簡單回復(fù)消息發(fā)送失敗給發(fā)送者,讓發(fā)送者手動重發(fā)告私。對于后續(xù)流程屎暇,如下:

1.如果對方不在線,就不推送通知驻粟,直接結(jié)束消息發(fā)送流程根悼,等待后續(xù)對方上線拉消息。這里就不用考慮存儲消息失敗的情況了蜀撑,因為存儲步驟在之前已保證ok挤巡。

2.對方在線,如果通知推送失敗怎么處理酷麦?對于沒推成功的情況矿卑,不再重推,等待下次上線拉消息沃饶!沒錯母廷,就是這么暴力和任性轻黑。

如此可能出現(xiàn)的問題是消息亂序走趋∫破龋客戶端可以根據(jù)消息在服務(wù)端的生成時間排序,可以解決這個問題嗡贺。就是會出現(xiàn)消息突然跳躍順序业舍。

在實現(xiàn)中抖拦,客戶端拉消息應(yīng)該是按照msgid范圍拉一批消息,而且在服務(wù)端的實現(xiàn)中舷暮,msgid要保證遞增态罪,無重復(fù)〗烹梗客戶端重新聯(lián)網(wǎng)后應(yīng)先保證處理拉服務(wù)器消息的流程先走完向臀,再處理新的消息通知。防止新的消息打亂上次的拉取邏輯诸狭,中間出現(xiàn)丟消息的情況券膀。

另外一個問題是服務(wù)器連續(xù)推過來n條消息通知,客戶端是不是應(yīng)答這n條消息通知驯遇,去拉n次芹彬?因為客戶端一次會拉一批消息,或許處理第一條的消息通知就已經(jīng)把后續(xù)的新消息都拉下來了叉庐,后面的拉取就成了重復(fù)動作舒帮,會導(dǎo)致消息拉重復(fù)了。這種問題也好解決陡叠,從服務(wù)器拉取回來后玩郊,判斷最大msgid是否比收到的通知中msgid要大,如果是枉阵,就忽略小的通知译红,不拉。如果拉到的最大msgid要比通知里的msgid小兴溜,就應(yīng)該繼續(xù)拉取侦厚。當(dāng)然,客戶端對消息的重復(fù)過濾邏輯還是要有的拙徽。

這樣的做法是在網(wǎng)絡(luò)交互上刨沦,多了一步通知和拉取,耗費(fèi)一些客戶端的流量膘怕。服務(wù)端的實現(xiàn)邏輯復(fù)雜度大大降低想诅,客戶端需要多處理一些邏輯。

這兩種方案,我個人傾向于拉的方式侧蘸。然后其中有幾個技術(shù)實現(xiàn)細(xì)節(jié)后續(xù)再寫裁眯。比如如何保證在分布式環(huán)境下msgid連續(xù)遞增不重復(fù),如何保證客戶端對消息的排序讳癌,消息同步的具體方案,服務(wù)端對消息的存儲等存皂。

總體而言晌坤,推的方案,服務(wù)端需要處理復(fù)雜的邏輯旦袋,客戶端需要處理的相對較少骤菠。拉的方案,服務(wù)端需要處理的邏輯比較簡單疤孕,客戶端需要配合做一些保證商乎。對于消息可靠的保證方面,個人傾向于拉的方案祭阀,更靠譜鹉戚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市专控,隨后出現(xiàn)的幾起案子抹凳,更是在濱河造成了極大的恐慌,老刑警劉巖伦腐,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赢底,死亡現(xiàn)場離奇詭異,居然都是意外死亡柏蘑,警方通過查閱死者的電腦和手機(jī)幸冻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咳焚,“玉大人洽损,你說我怎么就攤上這事∏埽” “怎么了趁啸?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長督惰。 經(jīng)常有香客問我不傅,道長,這世上最難降的妖魔是什么赏胚? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任访娶,我火速辦了婚禮,結(jié)果婚禮上觉阅,老公的妹妹穿的比我還像新娘崖疤。我一直安慰自己秘车,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布劫哼。 她就那樣靜靜地躺著叮趴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪权烧。 梳的紋絲不亂的頭發(fā)上眯亦,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機(jī)與錄音般码,去河邊找鬼妻率。 笑死,一個胖子當(dāng)著我的面吹牛板祝,可吹牛的內(nèi)容都是我干的宫静。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼券时,長吁一口氣:“原來是場噩夢啊……” “哼孤里!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起革为,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤扭粱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后震檩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琢蛤,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年抛虏,在試婚紗的時候發(fā)現(xiàn)自己被綠了博其。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡迂猴,死狀恐怖慕淡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沸毁,我是刑警寧澤峰髓,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站息尺,受9級特大地震影響携兵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜搂誉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一徐紧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦并级、人聲如沸拂檩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稻励。三九已至,卻和暖如春呀潭,著一層夾襖步出監(jiān)牢的瞬間钉迷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工钠署, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荒椭。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓谐鼎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親趣惠。 傳聞我的和親對象是個殘疾皇子狸棍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容