為什么說(shuō)基于TCP的移動(dòng)端仍然需要心跳?;??

前言

很多人認(rèn)為,TCP協(xié)議自身先天就有KeepAlive機(jī)制,為何基于它的通訊鏈接,仍然需要在應(yīng)用層實(shí)現(xiàn)額外的心跳?;?/code>?本文將從移動(dòng)端IM實(shí)踐的角度告訴你,即使使用的是TCP協(xié)議,應(yīng)用層的心跳?;钊耘f必不可少。

什么是心跳保活?

1.jpeg

在使用 TCP 長(zhǎng)連接的 IM 服務(wù)設(shè)計(jì)中,往往都會(huì)涉及到心跳。心跳一般是指某端(絕大多數(shù)情況下是客戶(hù)端)每隔一定時(shí)間向?qū)Χ税l(fā)送自定義指令,以判斷雙方是否存活,因其按照一定間隔發(fā)送,類(lèi)似于心跳,故被稱(chēng)為心跳指令。

TCP協(xié)議不是自帶KeepAlive的嗎?

那么問(wèn)題就隨之而來(lái)了:為什么需要在應(yīng)用層做心跳,難道 TCP 不是個(gè)可靠連接嗎?我們不能夠依賴(lài) TCP 做斷線(xiàn)檢測(cè)嗎?比如使用 TCP 的 KeepAlive 機(jī)制來(lái)實(shí)現(xiàn)。應(yīng)用層心跳是目前的最佳實(shí)踐嗎?怎么樣的心跳才是最佳實(shí)踐。

IM中保持有效長(zhǎng)連接的重要性

對(duì)于客戶(hù)端而言,使用 TCP 長(zhǎng)連接來(lái)實(shí)現(xiàn)業(yè)務(wù)的最大驅(qū)動(dòng)力在于:在當(dāng)前連接可用的情況下,每一次請(qǐng)求都只是簡(jiǎn)單的數(shù)據(jù)發(fā)送和接受,免去了 DNS 解析,連接建立等時(shí)間,大大加快了請(qǐng)求的速度,同時(shí)也有利于接受服務(wù)器的實(shí)時(shí)消息。但前提是連接可用。

如果連接無(wú)法很好地保持,每次請(qǐng)求就會(huì)變成撞大運(yùn):運(yùn)氣好,通過(guò)長(zhǎng)連接發(fā)送請(qǐng)求并收到反饋。運(yùn)氣差,當(dāng)前連接已失效,請(qǐng)求遲遲沒(méi)有收到反饋直到超時(shí),又需要一次連接建立的過(guò)程,其效率甚至還不如 HTTP。而連接保持的前提必然是檢測(cè)連接的可用性,并在連接不可用時(shí)主動(dòng)放棄當(dāng)前連接并建立新的連接。

基于這個(gè)前提,必須要有一種機(jī)制用于檢測(cè)連接可用性。同時(shí)移動(dòng)網(wǎng)絡(luò)的特殊性也要求客戶(hù)端需要在空余時(shí)間發(fā)送一定的信令,避免連接被回收。

而對(duì)于服務(wù)器而言,能夠及時(shí)獲悉連接可用性也非常重要:一方面服務(wù)器需要及時(shí)清理無(wú)效連接以減輕負(fù)載,另一方面也是業(yè)務(wù)的需求,如游戲副本中服務(wù)器需要及時(shí)處理玩家掉線(xiàn)帶來(lái)的問(wèn)題。

TCP的KeepAlive無(wú)法?替代應(yīng)用層心跳保活機(jī)制的原因

上面說(shuō)了保持連接的重要性,那么現(xiàn)在回到具體實(shí)現(xiàn)上。為什么我們需要使用應(yīng)用層心跳來(lái)做檢測(cè),而不是直接使用 TCP 的特性呢?

我們知道 TCP 是一個(gè)基于連接的協(xié)議,其連接狀態(tài)是由一個(gè)狀態(tài)機(jī)進(jìn)行維護(hù),連接完畢后,雙方都會(huì)處于 established 狀態(tài),這之后的狀態(tài)并不會(huì)主動(dòng)進(jìn)行變化。這意味著如果上層不進(jìn)行任何調(diào)用,一直使 TCP 連接空閑,那么這個(gè)連接雖然沒(méi)有任何數(shù)據(jù),但仍是保持連接狀態(tài),一天、一星期、甚至一個(gè)月,即使在這期間中間路由崩潰重啟無(wú)數(shù)次。舉個(gè)現(xiàn)實(shí)中經(jīng)常遇到的栗子:當(dāng)我們 ssh 到自己的 VPS 上,然后不小心踢掉網(wǎng)線(xiàn),此時(shí)的網(wǎng)絡(luò)變化并不會(huì)被 TCP 檢測(cè)出,當(dāng)我們重新插回網(wǎng)線(xiàn),仍舊可以正常使用 ssh,同時(shí)此時(shí)并沒(méi)有發(fā)生任何 TCP 的重連。

有人會(huì)說(shuō) TCP 不是有 KeepAlive 機(jī)制么,通過(guò)這個(gè)機(jī)制來(lái)實(shí)現(xiàn)不就可以了嗎?但是事實(shí)上,TCP KeepAlive 的機(jī)制其實(shí)并不適用于此。Keep Alive 機(jī)制開(kāi)啟后,TCP 層將在定時(shí)時(shí)間到后發(fā)送相應(yīng)的 KeepAlive 探針以確定連接可用性。一般時(shí)間為 7200 s(詳情請(qǐng)參見(jiàn)《TCP/IP詳解》中第23章),失敗后重試 10 次,每次超時(shí)時(shí)間 75 s。顯然默認(rèn)值無(wú)法滿(mǎn)足我們的需求,而修改過(guò)設(shè)置后就可以滿(mǎn)足了嗎?答案仍舊是否定的。

因?yàn)?TCP KeepAlive 是用于檢測(cè)連接的死活,而心跳機(jī)制則附帶一個(gè)額外的功能:檢測(cè)通訊雙方的存活狀態(tài)。兩者聽(tīng)起來(lái)似乎是一個(gè)意思,但實(shí)際上卻大相徑庭。

考慮一種情況,某臺(tái)服務(wù)器因?yàn)槟承┰驅(qū)е仑?fù)載超高,CPU 100%,無(wú)法響應(yīng)任何業(yè)務(wù)請(qǐng)求,但是使用 TCP 探針則仍舊能夠確定連接狀態(tài),這就是典型的連接活著但業(yè)務(wù)提供方已死的狀態(tài),對(duì)客戶(hù)端而言,這時(shí)的最好選擇就是斷線(xiàn)后重新連接其他服務(wù)器,而不是一直認(rèn)為當(dāng)前服務(wù)器是可用狀態(tài),一直向當(dāng)前服務(wù)器發(fā)送些必然會(huì)失敗的請(qǐng)求。

從上面我們可以知道,KeepAlive 并不適用于檢測(cè)雙方存活的場(chǎng)景,這種場(chǎng)景還得依賴(lài)于應(yīng)用層的心跳。應(yīng)用層心跳有著更大的靈活性,可以控制檢測(cè)時(shí)機(jī),間隔和處理流程,甚至可以在心跳包上附帶額外信息。從這個(gè)角度而言,應(yīng)用層的心跳的確是最佳實(shí)踐。

心跳?;顧C(jī)制的實(shí)現(xiàn)方案參考

從上面我們可以得出結(jié)論,目前而言,應(yīng)用層心跳的確是檢測(cè)連接有效性,雙方是否存活的最佳實(shí)踐,那么剩下的問(wèn)題就是怎么實(shí)現(xiàn)。

最簡(jiǎn)單粗暴做法當(dāng)然是定時(shí)心跳,如每隔 30 秒心跳一次,15 秒內(nèi)沒(méi)有收到心跳回包則認(rèn)為當(dāng)前連接已失效,斷開(kāi)連接并進(jìn)行重連。這種做法最直接,實(shí)現(xiàn)也簡(jiǎn)單。唯一的問(wèn)題是比較耗電和耗流量。以一個(gè)協(xié)議包 5 個(gè)字節(jié)計(jì)算,一天收發(fā) 2880 個(gè)心跳包,一個(gè)月就是 5 * 2 * 2880 * 30 = 0.8 M 的流量,如果手機(jī)上多裝幾個(gè) IM 軟件,每個(gè)月光心跳就好幾兆流量沒(méi)了,更不用說(shuō)頻繁的心跳帶來(lái)的電量損耗。

既然頻繁心跳會(huì)帶來(lái)耗電和耗流量的弊端,改進(jìn)的方向自然是減少心跳頻率,但也不能過(guò)于影響連接檢測(cè)的實(shí)時(shí)性。基于這個(gè)需求,一般可以將心跳間隔根據(jù)程序狀態(tài)進(jìn)行調(diào)整,當(dāng)程序在后臺(tái)時(shí)(這里主要考慮安卓),盡量拉長(zhǎng)心跳間隔,5 分鐘、甚至 10 分鐘都可以。

而當(dāng) App 在前臺(tái)時(shí)則按照原來(lái)規(guī)則操作。連接可靠性的判斷也可以放寬,避免一次心跳超時(shí)就認(rèn)為連接無(wú)效的情況,使用錯(cuò)誤積累,只在心跳超時(shí) n 次后才判定當(dāng)前連接不可用。當(dāng)然還有一些小 trick 比如從收到的最后一個(gè)指令包進(jìn)行心跳包周期計(jì)時(shí)而不是固定時(shí)間,這樣也能夠一定程度減少心跳次數(shù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、TCP狀態(tài)linux查看tcp的狀態(tài)命令:1)、netstat -nat 查看TCP各個(gè)狀態(tài)的數(shù)量2)、lso...
    北辰青閱讀 9,701評(píng)論 0 11
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評(píng)論 19 139
  • 18.1 引言 TCP是一個(gè)面向連接的協(xié)議。無(wú)論哪一方向另一方發(fā)送數(shù)據(jù)之前,都必須先在雙方之間建立一條連接。本章將...
    張芳濤閱讀 3,521評(píng)論 0 13
  • 長(zhǎng)連接和心跳那些事兒 簡(jiǎn)書(shū) 滌生。轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處,謝謝!如果讀完覺(jué)得有收獲的話(huà),歡迎點(diǎn)贊加關(guān)注。 介紹 長(zhǎng)連接...
    滌生YQ閱讀 11,780評(píng)論 2 69
  • ?我走過(guò)你走過(guò)的路算不算重逢 ,我吹過(guò)你吹過(guò)的風(fēng)算不算相擁! 姑娘,我在這條小巷見(jiàn)過(guò)你, 穿著花裙子,陽(yáng)光下的微笑...
    貳十三先生閱讀 485評(píng)論 6 7

友情鏈接更多精彩內(nèi)容