不少人認爲,TCP協議自身先天就有KeepAlive機制,爲什麼基於它的通信連接,仍然須要在應用層實現額外的心跳保活?本文將從移動端IM實踐的角度告訴你,即便使用的是TCP協議,應用層的心跳保活仍舊必不可少。
有關TCP協議的權威理論介紹,請參見《TCP/IP詳解》這本書。php
說明:本文引用了網易雲信項望烽的技術文章,感謝分享。 (本文同步發佈於:http://www.52im.net/thread-33-1-1.html)html
- 即時通信開發交流羣: 215891622 [推薦]android
- 移動端IM開發推薦文章:《新手入門一篇就夠:從零開發移動端IM》算法
《TCP/IP詳解 - 第11章·UDP:用戶數據報協議》
《TCP/IP詳解 - 第17章·TCP:傳輸控制協議》
《TCP/IP詳解 - 第18章·TCP鏈接的創建與終止》
《TCP/IP詳解 - 第21章·TCP的超時與重傳》
《通俗易懂-深刻理解TCP協議(上):理論基礎》
《通俗易懂-深刻理解TCP協議(下):RTT、滑動窗口、擁塞處理》
《理論經典:TCP協議的3次握手與4次揮手過程詳解》
《計算機網絡通信協議關係圖(中文珍藏版)》
《NAT詳解:基本原理、穿越技術(P2P打洞)、端口老化等》編程
作移動端IM多年以來,常常會與相關人員進行討論和交流。也常常會碰到些較真的技術人員詢問技術細節,如主流的移動端IM如何作心跳、如何保證消息必達、如何加快文件上傳等。由於平時工做太忙,沒有時間深刻整理和總結,每每只能簡略介紹,並不能具體展開,因而決定寫成文字,也有了有關移動 IM 問題處理的系列文章。安全
在使用 TCP 長鏈接的 IM 服務設計中,每每都會涉及到心跳。心跳通常是指某端(絕大多數狀況下是客戶端)每隔必定時間向對端發送自定義指令,以判斷雙方是否存活,因其按照必定間隔發送,相似於心跳,故被稱爲心跳指令。
有興趣瞭解IM/推送的心跳保活技術的文章,請參見:
《Android進程保活詳解:一篇文章解決你的全部疑問》
《Android端消息推送總結:實現原理、心跳保活、遇到的問題等》
《微信團隊原創分享:Android版微信後臺保活實戰分享(進程保活篇)》
《微信團隊原創分享:Android版微信後臺保活實戰分享(網絡保活篇)》
《移動端IM實踐:實現Android版微信的智能心跳機制》
《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》
>> 更多同類文章 ……服務器
那麼問題就隨之而來了:爲何須要在應用層作心跳,難道 TCP 不是個可靠鏈接嗎?咱們不可以依賴 TCP 作斷線檢測嗎?好比使用 TCP 的 KeepAlive 機制來實現。應用層心跳是目前的最佳實踐嗎?怎麼樣的心跳纔是最佳實踐。
不少作移動端IM的同行,之前確實沒有仔細考慮過這些問題,潛意識裏想固然的認爲這僅僅只是個簡單的心跳而已啊。好吧,事實並不是這麼簡單,請繼續往下看。微信
對於客戶端而言,使用 TCP 長鏈接來實現業務的最大驅動力在於:在當前鏈接可用的狀況下,每一次請求都只是簡單的數據發送和接受,免去了 DNS 解析,鏈接創建等時間,大大加快了請求的速度,同時也有利於接受服務器的實時消息。但前提是鏈接可用。
若是鏈接沒法很好地保持,每次請求就會變成撞大運:運氣好,經過長鏈接發送請求並收到反饋。運氣差,當前鏈接已失效,請求遲遲沒有收到反饋直到超時,又須要一次鏈接創建的過程,其效率甚至還不如 HTTP。而鏈接保持的前提必然是檢測鏈接的可用性,並在鏈接不可用時主動放棄當前鏈接並創建新的鏈接。
基於這個前提,必需要有一種機制用於檢測鏈接可用性。同時移動網絡的特殊性也要求客戶端須要在空餘時間發送必定的信令,避免鏈接被回收。詳見微信和運營商的撕B(另外一篇針對微信的信令風暴技術研究文章請見:《微信對網絡影響的技術試驗及分析》)。
而對於服務器而言,可以及時獲悉鏈接可用性也很是重要:一方面服務器須要及時清理無效鏈接以減輕負載,另外一方面也是業務的需求,如遊戲副本中服務器須要及時處理玩家掉線帶來的問題。網絡
上面說了保持鏈接的重要性,那麼如今回到具體實現上。爲何咱們須要使用應用層心跳來作檢測,而不是直接使用 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 並不適用於檢測雙方存活的場景,這種場景還得依賴於應用層的心跳。應用層心跳有着更大的靈活性,能夠控制檢測時機,間隔和處理流程,甚至能夠在心跳包上附帶額外信息。從這個角度而言,應用層的心跳的確是最佳實踐。架構
從上面咱們能夠得出結論,目前而言,應用層心跳的確是檢測鏈接有效性,雙方是否存活的最佳實踐,那麼剩下的問題就是怎麼實現。
最簡單粗暴作法固然是定時心跳,如每隔 30 秒心跳一次,15 秒內沒有收到心跳回包則認爲當前鏈接已失效,斷開鏈接並進行重連。這種作法最直接,實現也簡單。惟一的問題是比較耗電和耗流量。以一個協議包 5 個字節計算,一天收發 2880 個心跳包,一個月就是 5 * 2 * 2880 * 30 = 0.8 M 的流量,若是手機上多裝幾個 IM 軟件,每月光心跳就好幾兆流量沒了,更不用說頻繁的心跳帶來的電量損耗。
既然頻繁心跳會帶來耗電和耗流量的弊端,改進的方向天然是減小心跳頻率,但也不能過於影響鏈接檢測的實時性。基於這個需求,通常能夠將心跳間隔根據程序狀態進行調整,當程序在後臺時(這裏主要考慮安卓),儘可能拉長心跳間隔,5 分鐘、甚至 10 分鐘均可以。
而當 App 在前臺時則按照原來規則操做。鏈接可靠性的判斷也能夠放寬,避免一次心跳超時就認爲鏈接無效的狀況,使用錯誤積累,只在心跳超時 n 次後才斷定當前鏈接不可用。固然還有一些小 trick 好比從收到的最後一個指令包進行心跳包週期計時而不是固定時間,這樣也可以必定程度減小心跳次數。
(本文同步發佈於:http://www.52im.net/thread-33-1-1.html)
[1] 更多網絡編程基礎資料:
《理論聯繫實際:Wireshark抓包分析TCP 3次握手、4次揮手過程》
《UDP中一個包的大小最大能多大?》
《Java新一代網絡編程模型AIO原理及Linux系統AIO介紹》
《NIO框架入門(三):iOS與MINA二、Netty4的跨平臺UDP雙向通訊實戰》
《NIO框架入門(四):Android與MINA二、Netty4的跨平臺UDP雙向通訊實戰》
>> 更多同類文章 ……
[2] 有關IM/推送的通訊格式、協議的選擇:
《爲何QQ用的是UDP協議而不是TCP協議?》
《移動端即時通信協議選擇:UDP仍是TCP?》
《如何選擇即時通信應用的數據傳輸格式》
《強列建議將Protobuf做爲你的即時通信應用數據傳輸格式》
《移動端IM開發須要面對的技術問題(含通訊協議選擇)》
《簡述移動端IM開發的那些坑:架構設計、通訊協議和客戶端》
《理論聯繫實際:一套典型的IM通訊協議設計詳解》
《58到家實時消息系統的協議設計等技術實踐分享》
>> 更多同類文章 ……
[4] 有關WEB端即時通信開發:
《新手入門貼:史上最全Web端即時通信技術原理詳解》
《Web端即時通信技術盤點:短輪詢、Comet、Websocket、SSE》
《SSE技術詳解:一種全新的HTML5服務器推送事件技術》
《Comet技術詳解:基於HTTP長鏈接的Web端實時通訊技術》
《WebSocket詳解(一):初步認識WebSocket技術》
《socket.io實現消息推送的一點實踐及思路》
>> 更多同類文章 ……
[5] 有關IM架構設計:
《淺談IM系統的架構設計》
《簡述移動端IM開發的那些坑:架構設計、通訊協議和客戶端》
《一套原創分佈式即時通信(IM)系統理論架構方案》
《從零到卓越:京東客服即時通信系統的技術架構演進歷程》
《蘑菇街即時通信/IM服務器開發之架構選擇》
《騰訊QQ1.4億在線用戶的技術挑戰和架構演進之路PPT》
《微信技術總監談架構:微信之道——大道至簡(演講全文)》
《如何解讀《微信技術總監談架構:微信之道——大道至簡》》
《快速裂變:見證微信強大後臺架構從0到1的演進歷程(一)》
《17年的實踐:騰訊海量產品的技術方法論》
>> 更多同類文章 ……
[6] 有關IM安全的文章:
《即時通信安全篇(一):正確地理解和使用Android端加密算法》
《即時通信安全篇(二):探討組合加密算法在IM中的應用》
《即時通信安全篇(三):經常使用加解密算法與通信安全講解》
《即時通信安全篇(四):實例分析Android中密鑰硬編碼的風險》
《傳輸層安全協議SSL/TLS的Java平臺實現簡介和Demo演示》
《理論聯繫實際:一套典型的IM通訊協議設計詳解(含安全層設計)》
《微信新一代通訊安全解決方案:基於TLS1.3的MMTLS詳解》
《來自阿里OpenIM:打造安全可靠即時通信服務的技術實踐分享》
>> 更多同類文章 ……
[7] 有關實時音視頻開發:
《即時通信音視頻開發(一):視頻編解碼之理論概述》
《即時通信音視頻開發(二):視頻編解碼之數字視頻介紹》
《即時通信音視頻開發(三):視頻編解碼之編碼基礎》
《即時通信音視頻開發(四):視頻編解碼之預測技術介紹》
《即時通信音視頻開發(五):認識主流視頻編碼技術H.264》
《即時通信音視頻開發(六):如何開始音頻編解碼技術的學習》
《即時通信音視頻開發(七):音頻基礎及編碼原理入門》
《即時通信音視頻開發(八):常見的實時語音通信編碼標準》
《即時通信音視頻開發(九):實時語音通信的迴音及迴音消除概述》
《即時通信音視頻開發(十):實時語音通信的迴音消除技術詳解》
《即時通信音視頻開發(十一):實時語音通信丟包補償技術詳解》
《即時通信音視頻開發(十二):多人實時音視頻聊天架構探討》
《即時通信音視頻開發(十三):實時視頻編碼H.264的特色與優點》
《即時通信音視頻開發(十四):實時音視頻數據傳輸協議介紹》
《即時通信音視頻開發(十五):聊聊P2P與實時音視頻的應用狀況》
《即時通信音視頻開發(十六):移動端實時音視頻開發的幾個建議》
《即時通信音視頻開發(十七):視頻編碼H.26四、V8的前世此生》
《簡述開源實時音視頻技術WebRTC的優缺點》
《良心分享:WebRTC 零基礎開發者教程(中文)》
>> 更多同類文章 ……
[8] IM開發綜合文章:
《移動端IM開發須要面對的技術問題》
《開發IM是本身設計協議用字節流好仍是字符流好?》
《請問有人知道語音留言聊天的主流實現方式嗎?》
《IM系統中如何保證消息的可靠投遞(即QoS機制)》
《談談移動端 IM 開發中登陸請求的優化》
《徹底自已開發的IM該如何設計「失敗重試」機制?》
《微信對網絡影響的技術試驗及分析(論文全文)》
《即時通信系統的原理、技術和應用(技術論文)》
《開源IM工程「蘑菇街TeamTalk」的現狀:一場虎頭蛇尾的開源秀》
>> 更多同類文章 ……
[9] 開源移動端IM技術框架資料:
《開源移動端IM技術框架MobileIMSDK:快速入門》
《開源移動端IM技術框架MobileIMSDK:常見問題解答》
《開源移動端IM技術框架MobileIMSDK:壓力測試報告》
>> 更多同類文章 ……
[10] 有關推送技術的文章:
《iOS的推送服務APNs詳解:設計思路、技術原理及缺陷等》
《Android端消息推送總結:實現原理、心跳保活、遇到的問題等》
《掃盲貼:認識MQTT通訊協議》
《一個基於MQTT通訊協議的完整Android推送Demo》
《求教android消息推送:GCM、XMPP、MQTT三種方案的優劣》
《移動端實時消息推送技術淺析》
《掃盲貼:淺談iOS和Android後臺實時消息推送的原理和區別》
《絕對乾貨:基於Netty實現海量接入的推送服務技術要點》
《移動端IM實踐:谷歌消息推送服務(GCM)研究(來自微信)》
《爲什麼微信、QQ這樣的IM工具不使用GCM服務推送消息?》
>> 更多同類文章 ……
[11] 更多即時通信技術好文分類:
http://www.52im.net/forum.php?mod=collection&op=all