前言
很多人認為,TCP協(xié)議有KeepAlive機制,為何基于它的通訊鏈接仍然需要在應(yīng)用層實現(xiàn)額外的心跳保活呢?本文將從移動端IM的角度告訴你,即使使用的是TCP協(xié)議,應(yīng)用層的心跳保活仍舊必不可少。
什么是心跳
在使用TCP長連接的IM服務(wù)設(shè)計中,往往都會涉及到心跳。心跳一般是指客戶端每隔一定時間向服務(wù)端發(fā)送自定義指令,以判斷雙方是否存活,因其按照一定間隔發(fā)送,類似于心跳,故稱為心跳指令。
TCP的KeepAlive無法替代應(yīng)用層心跳保活機制的原因
TCP是一個基于連接的協(xié)議,其連接狀態(tài)是由一個狀態(tài)機進行維護,連接完畢(三次握手)后,雙方都會處于established狀態(tài),這之后的狀態(tài)并不會主動進行變化。也就是說,即使上層不進行任何調(diào)用,一直使TCP連接空閑,那么它仍然是保持連接的狀態(tài)。這個時候就需要一種機制來檢測TCP連接的狀態(tài),KeepAlive就是背負這個使命出現(xiàn)的。
那么問題來了,KeepAlive是用來檢測TCP連接狀態(tài)的,那為什么還需要心跳呢?這里就需要考慮一種情況了,假如某臺服務(wù)器因為某些原因?qū)е仑撦d超高,CPU100%,無法響應(yīng)任何業(yè)務(wù)需求,但是使用TCP探針仍舊能夠確定連接狀態(tài),這就是典型的連接活著但業(yè)務(wù)提供方已死的狀態(tài),對客戶端而言,這時最好的選擇就是斷線后重新連接其他服務(wù)器,而不是一直認為當前服務(wù)器是可用狀態(tài),一直向當前服務(wù)器發(fā)送些必然后失敗的請求。
從上面我們可以知道,KeepAlive并不適合檢測雙方存活的場景,這種場景還得依賴于應(yīng)用層的心跳。應(yīng)用層的心跳有著更大的靈活性,可以控制檢測時機、間隔和處理流程,甚至可以在心跳包上附帶額外信息。從這個角度而言,應(yīng)用層的心跳的確是最佳實踐。
TCP KeepAlive用于檢測連接的死活,而心跳機制則附帶一個額外的功能:檢測通訊雙方的存活狀態(tài)。
心跳保活機制的實現(xiàn)方案參考
從上面我們可以得出結(jié)論,目前而言,應(yīng)用層心跳的確是檢測連接有效性,雙方是否存活的最佳實踐,那么剩下的問題就是怎么實現(xiàn)。
最簡單粗暴的方法是定時心跳,如每隔30秒心跳一次,15秒內(nèi)沒有收到心跳包則認為當前連接已失效,斷開連接并進行重連。這種做法最直接,實現(xiàn)也簡單。唯一的問題就是耗電和耗流量。以一個協(xié)議包 5 個字節(jié)計算,一天收發(fā) 2880 個心跳包,一個月就是 5 x 2 x 2880 x 30 = 0.8 M 的流量,如果手機上多裝幾個 IM 軟件,每個月光心跳就好幾兆流量沒了,更不用說頻繁的心跳帶來的電量損耗。
既然頻繁心跳會帶來耗電和耗流量的弊端,改進的方向自然就是減少心跳頻率,但也不能過于影響連接檢測的實時性。基于這個需求,一般可以將心跳間隔根據(jù)程序狀態(tài)進行調(diào)整,當程序在后臺時(這里主要指安卓),盡量拉長心跳間隔,5分鐘、甚至10分鐘都可以。
而當App在前臺時則按照原來規(guī)則操作。連接可靠性的判斷也可以放寬,避免一次心跳超時就認為連接無效的情況,使用錯誤積累,只在心跳超時n次后才判定當前連接不可用。