add by zhj:
TCP的心跳包默認是2小時發一次,頻次這么低,我理解是因為TCP是一個傳輸層協議,比較底層,上層很多應用層協議都用到它。如果TCP心跳間隔很短,那對系統性能可能產生比較大的影響。
如果應用層協議感覺這個間隔太長,那可以自己發心跳包。比如服務注冊中心與服務之間就是長連接,通過發送間隔比較短的心跳包(一般是秒級)來及時感知對方的狀態,根據狀態采取相應的動作。
原文:http://hengyunabc.github.io/why-we-need-heartbeat/
作者:橫雲斷嶺
TCP keep-alive的三個參數
用man命令,可以查看linux的tcp的參數:
1 |
man 7 tcp |
其中keep-alive相關的參數有三個:
1 |
tcp_keepalive_intvl (integer; default: 75; since Linux 2.4) |
這些的默認配置值在/proc/sys/net/ipv4 目錄下可以找到。
可以直接用cat來查看文件的內容,就可以知道配置的值了。
也可以通過sysctl命令來查看和修改:
1 |
# 查詢 |
上面三個是系統級的配置,在編程時有三個參數對應,可以覆蓋掉系統的配置:
1 |
TCP_KEEPCNT 覆蓋 tcp_keepalive_probes,默認9(次) |
tcp keep-alive的本質
TCP keep-alive probe
上面了解了tcp keep-alive的一些參數,下面來探究下其本質。
在遠程機器192.168.66.123上,用nc啟動一個TCP服務器:
1 |
nc -l 9999 |
在本地機器上,用python創建一個socket去連接,並且用wireshark抓包分析
1 |
import socket |
上面的程序,設置了TCP_KEEPIDLE為20,TCP_KEEPINTVL為1,系統默認的tcp_keepalive_probes是9。
當網絡正常,不做干擾時,wireshark抓包的數據是這樣的(注意看第二列Time):
可以看到,當3次握手完成之后,每隔20秒之后66.120發送了一個TCP Keep-Alive的數據包,然后66.123回應了一個TCP Keep-Alive ACK包。這個就是TCP keep-alive的實現原理了。
當發送了第一個TCP Keep-Alive包之后,撥掉192.168.66.123的網線,然后數據包是這樣子的:
可以看到,當遠程服務器192.168.66.123網絡失去連接之后,本地機器(192.168.66.120)每隔一秒重發了9次tcp keep-alive probe,最終認為這個TCP連接已經失效,發了一個RST包給192.168.66.123。
三個參數的具體意義
TCP_KEEPIDLE :這個參數是多久沒有發送數據時,開始發送Keep-Alive包的時間,也就是鏈路空閑時間。
TCP_KEEPINTVL:這個參數是指發送Keep-Alive probe后,對方多久沒有回應,然后重新再發送keep alive probe的時間間隔
TCP_KEEPCNT:這個參數指,連續發送多少次keep alive probe,對方沒有回應,認為連接已經失效的重試次數
如果不能理解或者有混淆,仔細對照下上面的兩張圖片就可以明白了。
為什么應用層需要heart beat/心跳包?
默認的tcp keep-alive超時時間太長
默認是7200秒,也就是2個小時。
socks proxy會讓tcp keep-alive失效
socks協議只管轉發TCP層具體的數據包,而不會轉發TCP協議內的實現細節的包(也做不到),參考socks_proxy。
所以,一個應用如果使用了socks代理,那么tcp keep-alive機制就失效了,所以應用要自己有心跳包。
socks proxy只是一個例子,真實的網絡很復雜,可能會有各種原因讓tcp keep-alive失效。
移動網絡需要信令保活
前兩年,微信信令事件很火,搜索下“微信 信令”或者“移動網絡 信令”可以查到很多相關文章。
這里附上一個鏈接:微信的大規模使用真的會過多占用信令,影響通訊穩定嗎?
總結
-
TCP keep-alive是通過在空閑時發送TCP Keep-Alive數據包,然后對方回應TCP Keep-Alive ACK來實現的。
-
為什么需要heart beat/心跳包?因為tcp keep-alive不能滿足人們的實時性的要求,就是這么簡單。
