什么是 TCP keepalive
TCP keepalive 概念很简单:当建立一个TCP连接时,会设置了一系列与该连接相关的定时器。其中有些定时器跟处理 keepalive 相关,在 keepalive 定时器倒计时变为零时,会给连接的另一方发送一个 keepalive 探针包(probe packet),包内没有数据且设置了 ACK 标识。
如果收到一个 keepalive 探针包的响应,说明连接是正常和有效的。TCP 可以处理只有协议头,但实际数据长度为零的数据包。这种机制是有用的,假如其他主机断开了连接,你可以及时注意到连接的断开。
如果 keepalive 探针没有响应,那么可以认为连接不是有效的,进而可以采取正确的操作。
TCP keepalive 的应用场景
KeepAlive 是非侵入性的,大多数情况下开启 keepalive 不会有其他风险。需要注意的是,这样做会带来额外的网络开销,例如会影响到路由器和防火墙。
- 检测实际断掉的连接
- 维持客户端与 NAT 间的活跃网络包
检测实际断掉的连接
设想 A、B 两端建有 TCP 连接:最开始是三次握手,A 发送 SYN 报文段给 B,B 响应 SYN/ACK 给 A,最后 A 发送 ACK 给 B。现在两端处于 established 状态,都在等待对方发送数据。如果此时 B 电源被拔掉,在没有发送任何数据的通知 A 的情况下,B 已经断开了连接。A 已经做好了准备接收数据,但不知道 B 已经宕机。之后 B 恢复供电并且系统重启,A 以为跟 B 的连接还是正常的。此时 A 试图给 B 发送数据,B 会回复 RST 包,这样 A 才关闭这个连接。
Keepalive 机制可以让 A 端避免出现上述的情况。实际上,如果连接双方有网络问题,keepalive 通过定时发送 keepalive 已经及时感知到连接断开。
_____ _____
| | | |
| A | | B |
|_____| |_____|
^ ^
|--->--->--->-------------- SYN -------------->--->--->---|
|---<---<---<------------ SYN/ACK ------------<---<---<---|
|--->--->--->-------------- ACK -------------->--->--->---|
| |
| system crash ---> X
|
| system restart ---> ^
| |
|--->--->--->-------------- PSH -------------->--->--->---|
|---<---<---<-------------- RST --------------<---<---<---|
| |
维持客户端与 NAT 间的活跃网络包
keepalive 另一个用途是阻止因网络连接不活跃(长时间没有数据包)而导致的连接断开。
很多网络设备,尤其是NAT路由器,由于其硬件的限制(例如内存、CPU处理能力),无法保持其上的所有连接,因此在必要的时候会在连接池中选择一些不活跃的连接踢掉。典型做法是LRU,把最久没有数据的连接给踢掉。通过使用 TCP KeepAlive 机制,可以让连接每隔一小段时间就产生一些 ACK 包,以降低被踢掉的风险,当然,这样的代价是额外的网络和 CPU 负担。
_____ _____ _____
| | | | | |
| A | | NAT | | B |
|_____| |_____| |_____|
^ ^ ^
|--->--->--->---|----------- SYN ------------->--->--->---|
|---<---<---<---|--------- SYN/ACK -----------<---<---<---|
|--->--->--->---|----------- ACK ------------->--->--->---|
| | |
| | <--- connection deleted from table |
| | |
|--->- PSH ->---| <--- invalid connection |
| | |
Linux 系统中的 keepalive
Linux 中跟 keepalive 相关的三个参数:
- tcp_keepalive_time
- tcp_keepalive_intvl
- tcp_keepalive_probes
tcp_keepalive_time
发送最后一个数据包(只包含 ACK 的包不认为是数据包)和发送第一个 probe 包之间间隔的时间
tcp_keepalive_intvl
发送两个 keepalive probe 包之间间隔多长
tcp_keepalive_probes
连续发几个 probe 包不回复才认为连接断了
默认值
# cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
# cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75
# cat /proc/sys/net/ipv4/tcp_keepalive_probes
9
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。