你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 為什麼說基於TCP的移動端IM仍然需要心跳保活?

為什麼說基於TCP的移動端IM仍然需要心跳保活?

編輯:IOS開發基礎

1、前言

有關TCP協議的權威理論介紹,請參見《TCP/IP詳解》這本書。

說明:本文引用了網易雲信項望烽的技術文章,感謝分享。 

2、學習交流

- 即時通訊開發交流群:215891622 [推薦]

- 移動端IM開發推薦文章:《新手入門一篇就夠:從零開發移動端IM》

3、參考資料

《TCP/IP詳解-第11章·UDP:用戶數據報協議》

《TCP/IP詳解-第17章·TCP:傳輸控制協議》

《TCP/IP詳解-第18章·TCP連接的建立與終止》

《TCP/IP詳解-第21章·TCP的超時與重傳》

《通俗易懂-深入理解TCP協議(上):理論基礎》

《通俗易懂-深入理解TCP協議(下):RTT、滑動窗口、擁塞處理》

《理論經典:TCP協議的3次握手與4次揮手過程詳解》

《計算機網絡通訊協議關系圖(中文珍藏版)》

《NAT詳解:基本原理、穿越技術(P2P打洞)、端口老化等》

4、本文源起

做移動端IM多年以來,經常會與相關人員進行討論和交流。也經常會碰到些較真的技術人員詢問技術細節,如主流的移動端IM如何做心跳、如何保證消息必達、如何加快文件上傳等。因為平時工作太忙,沒有時間深入整理和總結,往往只能簡略介紹,並不能具體展開,於是決定寫成文字,也有了有關移動 IM 問題處理的系列文章。

5、什麼是心跳保活?

152639a88oc4ohnuwp89ny.jpg

在使用 TCP 長連接的 IM 服務設計中,往往都會涉及到心跳。心跳一般是指某端(絕大多數情況下是客戶端)每隔一定時間向對端發送自定義指令,以判斷雙方是否存活,因其按照一定間隔發送,類似於心跳,故被稱為心跳指令。

有興趣了解IM/推送的心跳保活技術的文章,請參見:

《Android進程保活詳解:一篇文章解決你的所有疑問》

《Android端消息推送總結:實現原理、心跳保活、遇到的問題等》

《微信團隊原創分享:Android版微信後台保活實戰分享(進程保活篇)》

《微信團隊原創分享:Android版微信後台保活實戰分享(網絡保活篇)》

《移動端IM實踐:實現Android版微信的智能心跳機制》

《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》

>>更多同類文章 ……

6、TCP協議不是自帶KeepAlive的嗎?

那麼問題就隨之而來了:為什麼需要在應用層做心跳,難道 TCP 不是個可靠連接嗎?我們不能夠依賴 TCP 做斷線檢測嗎?比如使用 TCP 的 KeepAlive 機制來實現。應用層心跳是目前的最佳實踐嗎?怎麼樣的心跳才是最佳實踐。

很多做移動端IM的同行,以前確實沒有仔細考慮過這些問題,潛意識裡想當然的認為這僅僅只是個簡單的心跳而已啊。好吧,事實並非這麼簡單,請繼續往下看。

7、IM中保持有效長連接的重要性

對於客戶端而言,使用 TCP 長連接來實現業務的最大驅動力在於:在當前連接可用的情況下,每一次請求都只是簡單的數據發送和接受,免去了 DNS 解析,連接建立等時間,大大加快了請求的速度,同時也有利於接受服務器的實時消息。但前提是連接可用。

如果連接無法很好地保持,每次請求就會變成撞大運:運氣好,通過長連接發送請求並收到反饋。運氣差,當前連接已失效,請求遲遲沒有收到反饋直到超時,又需要一次連接建立的過程,其效率甚至還不如 HTTP。而連接保持的前提必然是檢測連接的可用性,並在連接不可用時主動放棄當前連接並建立新的連接。

基於這個前提,必須要有一種機制用於檢測連接可用性。同時移動網絡的特殊性也要求客戶端需要在空余時間發送一定的信令,避免連接被回收。詳見微信和運營商的撕B(另一篇針對微信的信令風暴技術研究文章請見:《微信對網絡影響的技術試驗及分析》)。

而對於服務器而言,能夠及時獲悉連接可用性也非常重要:一方面服務器需要及時清理無效連接以減輕負載,另一方面也是業務的需求,如游戲副本中服務器需要及時處理玩家掉線帶來的問題。

8、TCP的KeepAlive無法替代應用層心跳保活機制的原因

上面說了保持連接的重要性,那麼現在回到具體實現上。為什麼我們需要使用應用層心跳來做檢測,而不是直接使用 TCP 的特性呢?

我們知道 TCP 是一個基於連接的協議,其連接狀態是由一個狀態機進行維護,連接完畢後,雙方都會處於 established 狀態,這之後的狀態並不會主動進行變化。這意味著如果上層不進行任何調用,一直使 TCP 連接空閒,那麼這個連接雖然沒有任何數據,但仍是保持連接狀態,一天、一星期、甚至一個月,即使在這期間中間路由崩潰重啟無數次。舉個現實中經常遇到的栗子:當我們 ssh 到自己的 VPS 上,然後不小心踢掉網線,此時的網絡變化並不會被 TCP 檢測出,當我們重新插回網線,仍舊可以正常使用 ssh,同時此時並沒有發生任何 TCP 的重連。

有人會說 TCP 不是有 KeepAlive 機制麼,通過這個機制來實現不就可以了嗎?但是事實上,TCP KeepAlive 的機制其實並不適用於此。Keep Alive 機制開啟後,TCP 層將在定時時間到後發送相應的 KeepAlive 探針以確定連接可用性。一般時間為 7200 s(詳情請參見《TCP/IP詳解》中第23章),失敗後重試 10 次,每次超時時間 75 s。顯然默認值無法滿足我們的需求,而修改過設置後就可以滿足了嗎?答案仍舊是否定的。

因為 TCP KeepAlive 是用於檢測連接的死活,而心跳機制則附帶一個額外的功能:檢測通訊雙方的存活狀態。兩者聽起來似乎是一個意思,但實際上卻大相徑庭。

考慮一種情況,某台服務器因為某些原因導致負載超高,CPU 100%,無法響應任何業務請求,但是使用 TCP 探針則仍舊能夠確定連接狀態,這就是典型的連接活著但業務提供方已死的狀態,對客戶端而言,這時的最好選擇就是斷線後重新連接其他服務器,而不是一直認為當前服務器是可用狀態,一直向當前服務器發送些必然會失敗的請求。

從上面我們可以知道,KeepAlive 並不適用於檢測雙方存活的場景,這種場景還得依賴於應用層的心跳。應用層心跳有著更大的靈活性,可以控制檢測時機,間隔和處理流程,甚至可以在心跳包上附帶額外信息。從這個角度而言,應用層的心跳的確是最佳實踐。

9、心跳保活機制的實現方案參考

從上面我們可以得出結論,目前而言,應用層心跳的確是檢測連接有效性,雙方是否存活的最佳實踐,那麼剩下的問題就是怎麼實現。

最簡單粗暴做法當然是定時心跳,如每隔 30 秒心跳一次,15 秒內沒有收到心跳回包則認為當前連接已失效,斷開連接並進行重連。這種做法最直接,實現也簡單。唯一的問題是比較耗電和耗流量。以一個協議包 5 個字節計算,一天收發 2880 個心跳包,一個月就是 5 * 2 * 2880 * 30 = 0.8 M 的流量,如果手機上多裝幾個 IM 軟件,每個月光心跳就好幾兆流量沒了,更不用說頻繁的心跳帶來的電量損耗。

既然頻繁心跳會帶來耗電和耗流量的弊端,改進的方向自然是減少心跳頻率,但也不能過於影響連接檢測的實時性。基於這個需求,一般可以將心跳間隔根據程序狀態進行調整,當程序在後台時(這裡主要考慮安卓),盡量拉長心跳間隔,5 分鐘、甚至 10 分鐘都可以。

而當 App 在前台時則按照原來規則操作。連接可靠性的判斷也可以放寬,避免一次心跳超時就認為連接無效的情況,使用錯誤積累,只在心跳超時 n 次後才判定當前連接不可用。當然還有一些小 trick 比如從收到的最後一個指令包進行心跳包周期計時而不是固定時間,這樣也能夠一定程度減少心跳次數。



  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved