為什么基於TCP的應用需要心跳包(TCP keep-alive原理分析)


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
2
3
4
5
6
7
8
9
10
11
12
tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)
The number of seconds between TCP keep-alive probes.

tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
The maximum number of TCP keep-alive probes to send before giving up and killing the connection if no
response is obtained from the other end.

tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
The number of seconds a connection needs to be idle before TCP begins sending out keep-alive probes. Keep-
alives are sent only when the SO_KEEPALIVE socket option is enabled. The default value is 7200 seconds (2
hours). An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval
of 75 seconds apart) when keep-alive is enabled.

 

這些的默認配置值在/proc/sys/net/ipv4 目錄下可以找到。

可以直接用cat來查看文件的內容,就可以知道配置的值了。
也可以通過sysctl命令來查看和修改:

1
2
3
4
5
# 查詢
cat /proc/sys/net/ipv4/tcp_keepalive_time
sysctl net.ipv4.tcp_keepalive_time
#修改
sysctl net.ipv4.tcp_keepalive_time=3600

 

上面三個是系統級的配置,在編程時有三個參數對應,可以覆蓋掉系統的配置:

1
2
3
TCP_KEEPCNT 覆蓋  tcp_keepalive_probes,默認9(次)
TCP_KEEPIDLE 覆蓋 tcp_keepalive_time,默認7200(秒)
TCP_KEEPINTVL 覆蓋 tcp_keepalive_intvl,默認75(秒)

 

tcp keep-alive的本質

TCP keep-alive probe

上面了解了tcp keep-alive的一些參數,下面來探究下其本質。

在遠程機器192.168.66.123上,用nc啟動一個TCP服務器:

1
nc -l 9999

 

在本地機器上,用python創建一個socket去連接,並且用wireshark抓包分析

1
2
3
4
5
6
7
8
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 20)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1)

s.connect(('192.168.66.123', 9999))

 

上面的程序,設置了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不能滿足人們的實時性的要求,就是這么簡單。

橫雲斷嶺/hengyunabc wechat
歡迎您掃一掃上面的微信公眾號,訂閱橫雲斷嶺的專欄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM