移动IM开发指南2:心跳指令详解
《移動IM開發(fā)指南》系列文章將會介紹一個IM APP的方方面面,包括技術(shù)選型、登陸優(yōu)化等。此外,本文作者會結(jié)合他在網(wǎng)易云信多年iOS IMSDK開發(fā)的經(jīng)驗,深度分析實際開發(fā)中的各種常見問題。
?
推薦閱讀
移動IM開發(fā)指南1:如何進行技術(shù)選型
移動IM開發(fā)指南3:如何優(yōu)化登錄模塊
?
心跳指令是什么?
在使用 TCP 長連接的 IM 服務設計中,往往都會涉及到心跳。心跳一般是指某端(絕大多數(shù)情況下是客戶端)每隔一定時間向?qū)Χ税l(fā)送自定義指令,以判斷雙方是否存活,因其按照一定間隔發(fā)送,類似于心跳,故被稱為心跳指令。
?
為什么需要在應用層做心跳?
那么為什么需要在應用層做心跳,難道 TCP 不是個可靠連接嗎?我們不能夠依賴 TCP 做斷線檢測嗎?比如使用 TCP 的 KeepAlive 機制來實現(xiàn)。應用層心跳是目前的最佳實踐嗎?怎么樣的心跳才是最佳實踐?
是不是以前從來沒有仔細考慮過這些問題,僅僅只是個簡單的心跳而已啊!
對于客戶端而言,使用 TCP 長連接來實現(xiàn)業(yè)務的最大驅(qū)動力在于:在當前連接可用的情況下,每一次請求都只是簡單的數(shù)據(jù)發(fā)送和接受,免去了 DNS 解析,連接建立等時間,大大加快了請求的速度,同時也有利于接受服務器的實時消息。
但前提是連接可用。如果連接無法很好地保持,每次請求就會變成撞大運:運氣好,通過長連接發(fā)送請求并收到反饋。運氣差,當前連接已失效,請求遲遲沒有收到反饋直到超時,又需要一次連接建立的過程,其效率甚至還不如 HTTP。而連接保持的前提必然是檢測連接的可用性,并在連接不可用時主動放棄當前連接并建立新的連接。
基于這個前提,必須要有一種機制用于檢測連接可用性。同時移動網(wǎng)絡的特殊性也要求客戶端需要在空余時間發(fā)送一定的信令,避免連接被回收。詳見《微信和運營商的撕B》。
而對于服務器而言,能夠及時獲悉連接可用性也非常重要:一方面服務器需要及時清理無效連接以減輕負載,另一方面也是業(yè)務的需求,如游戲副本中服務器需要及時處理玩家掉線帶來的問題。
上面說了保持連接的重要性,那么現(xiàn)在回到具體實現(xiàn)上。為什么我們需要使用應用層心跳來做檢測,而不是直接使用 TCP 的特性呢?
我們知道 TCP 是一個基于連接的協(xié)議,其連接狀態(tài)是由一個狀態(tài)機進行維護,連接完畢后,雙方都會處于 established 狀態(tài),這之后的狀態(tài)并不會主動進行變化。這意味著如果上層不進行任何調(diào)用,一直使 TCP 連接空閑,那么這個連接雖然沒有任何數(shù)據(jù),但仍是保持連接狀態(tài),一天,一星期,甚至一個月,即使在這期間中間路由崩潰重啟無數(shù)次。舉個現(xiàn)實中經(jīng)常遇到的栗子:當我們 ssh 到自己的 VPS 上,然后不小心踢掉網(wǎng)線,此時的網(wǎng)絡變化并不會被 TCP 檢測出,當我們重新插回網(wǎng)線,仍舊可以正常使用 ssh,同時此時并沒有發(fā)生任何 TCP 的重連。
有人會說 TCP 不是有 KeepAlive 機制么,通過這個機制來實現(xiàn)不就可以了嗎?但是事實上,TCP KeepAlive 的機制其實并不適用于此。Keep Alive 機制開啟后,TCP 層將在定時時間到后發(fā)送相應的 KeepAlive 探針以確定連接可用性。一般時間為 7200 s,失敗后重試 10 次,每次超時時間 75 s。顯然默認值無法滿足我們的需求,而修改過設置后就可以滿足了嗎?答案仍舊是否定的。因為 TCP KeepAlive 是用于檢測連接的死活,而心跳機制則附帶一個額外的功能:檢測通訊雙方的存活狀態(tài)。兩者聽起來似乎是一個意思,但實際上卻大相徑庭。考慮一種情況,某臺服務器因為某些原因?qū)е仑撦d超高,CPU 100%,無法響應任何業(yè)務請求,但是使用 TCP 探針則仍舊能夠確定連接狀態(tài),這就是典型的連接活著但業(yè)務提供方已死的狀態(tài),對客戶端而言,這時的最好選擇就是斷線后重新連接其他服務器,而不是一直認為當前服務器是可用狀態(tài),一直向當前服務器發(fā)送些必然會失敗的請求。
從上面我們可以知道,KeepAlive 并不適用于檢測雙方存活的場景,這種場景還得依賴于應用層的心跳。應用層心跳有著更大的靈活性,可以控制檢測時機,間隔和處理流程,甚至可以在心跳包上附帶額外信息。從這個角度而言,應用層的心跳的確是最佳實踐。
?
如何實現(xiàn)心跳指令?
從上面我們可以得出結(jié)論,目前而言,應用層心跳的確是檢測連接有效性,雙方是否存活的最佳實踐,那么剩下的問題就是怎么實現(xiàn)。
最簡單粗暴做法當然是定時心跳,如每隔 30 秒心跳一次,15 秒內(nèi)沒有收到心跳回包則認為當前連接已失效,斷開連接并進行重連。這種做法最直接,實現(xiàn)也簡單。唯一的問題是比較耗電和耗流量。以一個協(xié)議包 5 個字節(jié)計算,一天收發(fā) 2880 個心跳包,一個月就是 5 * 2 * 2880 * 30 = 0.8 M 的流量,如果手機上多裝幾個 IM 軟件,每個月光心跳就好幾兆流量沒了,更不用說頻繁的心跳帶來的電量損耗。
既然頻繁心跳會帶來耗電和耗流量的弊端,改進的方向自然是減少心跳頻率,但也不能過于影響連接檢測的實時性。基于這個需求,一般可以將心跳間隔根據(jù)程序狀態(tài)進行調(diào)整,當程序在后臺時(這里主要考慮安卓),盡量拉長心跳間隔,5分鐘,甚至 10 分鐘都可以。而當 App 在前臺時則按照原來規(guī)則操作。連接可靠性的判斷也可以放寬,避免一次心跳超時就認為連接無效的情況,使用錯誤積累,只在心跳超時 n 次后才判定當前連接不可用。當然還有一些小 trick 比如從收到的最后一個指令包進行心跳包周期計時而不是固定時間,這樣也能夠一定程度減少心跳次數(shù)。
?
以上就是 網(wǎng)易云信對于心跳指令的理解和實踐,《移動IM開發(fā)指南》第三篇文章將為大家介紹如何優(yōu)化登錄模塊,敬請期待。總結(jié)
以上是生活随笔為你收集整理的移动IM开发指南2:心跳指令详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 移动IM开发指南1:如何进行技术选型
- 下一篇: 连麦互动直播方案全实践1:什么是连麦互动