TCP中已有SO_KEEPALIVE選項,為什麼還要在應用層加入心跳包機制??

SO_KEEPALIVE和應用層加入心跳包機制有什麼不同,各自的優勢和劣勢.

希望碩爺看到!!!


首先,我想說的是,SO_Keeplive是實現在伺服器側,客戶端被動響應,預設超時時間為120分鐘,這是RFC協議標準規範。

SO_Keeplive是實現在TCP協議棧(四層),應用層的心跳實現在第七層,本質沒有任何區別,但應用層需要自己來定義心跳包格式。

之所以實現在伺服器側,是因為與客戶端相比,伺服器側的壽命更長,因為伺服器側需要不間斷地提供服務,而客戶端可能由於用戶下班而合上電腦(TCP沒有來得及發送FIN關閉連接),這樣的話,伺服器側就會有很多不可用的TCP連接(established),這樣的連接依然會佔用伺服器內存資源,於是就設計這個keepalive 來檢測客戶端是否可用,如果幾次重傳keepalive ,客戶端沒有相應,刪除連接,釋放資源。

需要指出的是,超時時間是指TCP連接沒有任何數據、控制字傳輸的時間,如果有任何數據傳輸,會刷新定時器,重新走表。

TCP心跳是一個備受爭議的實現,只是一個option,不是強制標準。

之所以應用層需要獨立實現自己的心跳,是因為超時時間較長,無法給應用層提供快速的反饋。

所以類似BGP協議就獨立實現了自己的keepalive,最小可以設置一秒鐘,三次沒有應答即可以Reset連接,最快三秒可以檢測到失效。

而三秒依然太慢,可以用另外一個協議BFD來提供更快發現鏈路失效,最快可以配置成10ms
,三次超時(30ms)就可以完成失效檢測。


因為TCP協議中的SO_KEEPALIVE有幾個致命的缺陷:

  1. keepalive只能檢測連接是否存活,不能檢測連接是否可用。比如伺服器因為負載過高導致無法響應請求但是連接仍然存在,此時keepalive無法判斷連接是否可用。
  2. 如果TCP連接中的另一方因為停電突然斷網,我們並不知道連接斷開,此時發送數據失敗會進行重傳,由於重傳包的優先順序要高於keepalive的數據包,因此keepalive的數據包無法發送出去。只有在長時間的重傳失敗之後我們才能判斷此連接斷開了。

大概你們沒有遇到過需要使用四層負載均衡之類的中繼設備的情況,tcp_keepalive會終結到負載均衡上面,無法檢測遠端是否還連著。就算你能控制你自己的IP前面沒有"中繼設備,你也沒法控制客戶的網路會不會有個WAF或者sock5代理啥的。無法檢測服務是否可用也是很重要的點。


發送端無法區分:
1. 網路太慢
2. 另一端掛了
3. 還是另一端的響應邏輯太慢

這三種情況,需要邏輯層來區分

有位答主提到了陳碩的書,正好家裡有一本,拍了個照:


還希望陳碩看到。。
你是根本沒看他的書吧。
《Linux多線程服務端編程》書上9.3節已經說的不能再詳細了。


解決的問題不一樣。
tcp keepalive檢查連接是否存活。
應用keppalive檢測應用是否正常可響應。

舉個栗子。服務端死鎖,無法處理任何業務請求。但是操作系統仍然可以響應網路層keepalive包。


級別不一樣,比如資料庫壞掉了,應用程序失敗了,但是跟客戶端的tcp完好無損。


我拿實例來說明吧,保活機制目的是為了檢測線路狀況(比如連接斷開),應用層心跳機制是為了滿足業餘需求(比如下載任務)。(本想補充一下鏈路層的事情的,想想和問題無關還是算了)


tcp 的keepalive設計思想保證的是tcp協議連接的健全
並不能保證你寫的應用層的連接健全 你自己的應用還要你自己視情況自己寫心跳


為什麼要用心跳包我個人覺得在移動數據網路情景下最好解釋...

首先預設時間前面大佬已經說了這個就直接略過吧

預設時間很長是不是?那我們把時間改短能不能代替心跳包?

答案還是不能

KeepAlive實際上只是去檢查你這個連接是不是存活的 打個比方就是個管道 他來檢查你這個管道是不是能通水

那麼excited的地方就來了!你怎麼知道水廠能不能供水?

這就是個很典型的例子 連接是保持了 但是服務端卻無法處理業務,這個時候你覺得這個是存活還是不存活呢?

而心跳包不會有這個問題 他的職責就是檢查雙方的存活狀態,聽起來好像是一回事?但是實際上不一樣,正如之前所說KeepAlive查的是你這個連接是不是正常的 而心跳包是檢查雙方能不能正常交換數據~

TCP長連接從本質上來說,不需要心跳包來維持~ 但是有些奇葩情況下就是辣么坑爹

這個時候就不得不提到我一開始說的移動數據網路場景啦

現在運營商的移動數據多為NAT方式 然後有些策略大概意思就是在一定時間內沒有數據通過這個連接 他就直接給你砍啦~很坑爹是不是 這個時候心跳包就能起到一個保活的作用並且也能檢查雙方存活

心跳是一個可選的方案 至於用不用就要看你的業務需求啦

修仙時寫的 有錯誤歡迎指出(我覺得描述錯誤的可能性比較大的說 語文一直不太好)


最重要一點:

運營商會過濾掉keep包

這種錯查死你


網路協議棧分層的目的是什麼?是每一層做好自己該做的事情。TCP作為傳輸層協議,保證的是在host級別端對端的連接及可靠傳輸。作為應用層的協議,應該是獨立於TCP其上的,如果要保證兩個應用程序之間的所有feature就應該是由應用層本身定義及實現。
舉一個不相關的例子,既然Ethernet 實現了mac廣播和多播,那為什麼還需要IP層廣播和多播。這不是顯然是雞同鴨講嘛。
設計應用層就應該假設傳輸層是不可見不可隨意操作的並且可能出問題的外部API,否則到時候出問題排查起來都不知道是真的TCP層錯了還是應用層錯了。


準確評估鏈路狀態,快速回收無效連接。


一些業務場景需要應用層的心跳,比如:服務彙報自身的負載情況給中心結點(負載均衡)、IM客戶端上報本地最新消息的版本號(服務端再返回它的最新版本號)。


據說是電信提供商如果搞了各種劫持的話會影響到,所以還是得自己再做一個。


太慢了不靈活


推薦閱讀:

TCP面向位元組流和報文段的關係是什麼?
怎樣實時判斷socket鏈接狀態?
leader/follower, 半同步半非同步 和 事件驅動的關係是什麼?
你用socket寫過什麼有趣的程序?
Linux中本機和本機Socket通信會走網卡嗎?

TAG:C編程語言 | 計算機網路 | C | CC | Socket |