1、什么是 TCP Keepalive?
TCP Keepalive 是一种 TCP 协议内置的探测机制,用于检测长时间未活动的连接是否仍然存活。当启用了 Keepalive 后,TCP 会在连接空闲一定时间后,定期向对端发送探测包,如果未收到对端的响应,则会尝试多次探测,最终关闭连接。
用途
:
检测并清理死连接,防止资源长期占用。提高系统的可靠性,适用于长连接场景(如数据库连接、RPC 调用等)。快速感知网络断开,便于应用层及时处理。
2、 TCP Keepalive 的工作流程
大致工作流程
如下:
空闲时间检测:TCP 连接进入空闲状态超过 tcp_keepalive_time 后,开始发送探测包。
发送探测包:每隔 tcp_keepalive_intvl 秒发送一次探测包。
响应与失败处理:
• 如果对端响应,则认为连接正常;
• 如果连续发送 tcp_keepalive_probes 次探测包无响应,则认为连接已断开,关闭连接。
3、 TCP Keepalive 参数详解
TCP Keepalive 的核心参数可以通过 /proc/sys/net/ipv4/文件调整:
参数名称 | 默认值 | 参数含义 |
---|---|---|
tcp_keepalive_time | 7200 秒 | 连接空闲多久后开始发送探测包(秒) |
tcp_keepalive_intvl | 75 秒 | 探测包之间的间隔时间(秒) |
tcp_keepalive_probes | 9 次 | 探测失败前最多发送的探测包数量 |
示例:调整 Keepalive 参数(以 60 秒空闲时间为例):
sysctl -w net.ipv4.tcp_keepalive_time=60
sysctl -w net.ipv4.tcp_keepalive_intvl=10
sysctl -w net.ipv4.tcp_keepalive_probes=3
4. TCP Keepalive 的启用方式
TCP Keepalive 功能的启用分为两层:应用层启用和系统层配置。
4.1 应用层显式启用
TCP Keepalive 功能必须由应用程序显式调用 SO_KEEPALIVE 选项开启,操作系统参数仅作为默认配置,服务于已启用的应用。
在应用层中,可通过以下代码启用 Keepalive:
int keepalive = 1; // 开启 Keepalive
int keepidle = 60; // 空闲 60 秒后开始探测
int keepintvl = 10; // 每隔 10 秒探测一次
int keepcnt = 3; // 最多探测 3 次// 设置 SO_KEEPALIVE
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));// 设置 TCP_KEEPIDLE
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));// 设置 TCP_KEEPINTVL
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl));// 设置 TCP_KEEPCNT
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
4.2 系统层参数配置
如果应用层未显式启用 TCP Keepalive(如没有设置 SO_KEEPALIVE),仅调整系统参数(如 net.ipv4.tcp_keepalive_time)是无效的。系统参数的作用是为已启用 Keepalive 的连接提供默认行为,不能全局强制启用 Keepalive。
5. 客户端与服务端的 Keepalive 配置
5.1 客户端 Socket 连接场景
客户端需要显式在程序中启用 TCP Keepalive,例如:
Socket socket = new Socket();
socket.setKeepAlive(true); // 启用 Keepalive
或通过框架提供的配置项(如 Netty、Spring 等)启用 Keepalive。
5.2 服务端 Socket 监听场景
服务端可以通过套接字监听程序设置 Keepalive,适用于清理死连接的场景:
ServerSocket serverSocket = new ServerSocket(port);
serverSocket.setReuseAddress(true); // 可选
serverSocket.setKeepAlive(true); // 启用 Keepalive
对于使用 Nginx、Apache 等 Web 服务器的场景,可以通过配置文件显式启用 Keepalive。例如:
keepalive_timeout 60;
6. 如何确认 TCP Keepalive 是否生效
6.1 检查套接字选项
使用 ss 或 netstat 查看连接是否启用了 Keepalive:
ss -4no state established | grep 2379tcp 0 0 172.18.120.55:2379 172.18.120.56:52104 timer:(keepalive,19sec,0)
tcp 0 0 172.18.120.55:2379 172.18.20.153:48184 timer:(keepalive,14sec,0)
tcp 0 0 172.18.120.55:2379 172.18.120.55:49988 timer:(keepalive,6.493ms,0)
tcp 0 0 172.18.120.55:2379 172.18.120.56:52176 timer:(keepalive,3.549ms,0)
tcp 0 0 172.18.120.55:51590 172.18.20.153:2379 timer:(keepalive,11sec,0)
tcp 0 0 172.18.120.55:49878 172.18.120.55:2379 timer:(keepalive,9.693ms,0)
tcp 0 0 172.18.120.55:49564 172.18.20.153:2379 timer:(keepalive,9.565ms,0)
tcp 0 0 172.18.120.55:2379 172.18.120.56:50060 timer:(keepalive,17sec,0)
tcp 0 0 172.18.120.55:2379 172.18.120.55:48138 timer:(keepalive,17sec,0)
tcp 0 0 172.18.120.55:37618 172.18.20.153:2379 timer:(keepalive,2.845ms,0)
tcp 0 0 172.18.120.55:2379 172.18.20.153:53632 timer:(keepalive,18sec,0)
timer:(keepalive,19sec,0)
表示启用了 TCP Keepalive 功能,且计时器处于 Keepalive 状态。
keepalive:当前连接处于 Keepalive 探测模式。
19sec:距离下一次 Keepalive 探测还有 19 秒。
0:表明当前尚未检测到丢包(即 Keepalive 探测未失败)。
netstat -4npo | grep -i established | headtcp 0 0 172.18.120.55:2379 172.18.120.56:52104 ESTABLISHED 8072/etcd keepalive (11.02/0/0)
tcp 0 0 172.18.120.55:2379 172.18.20.153:48184 ESTABLISHED 8072/etcd keepalive (0.52/0/0)
tcp 0 0 172.18.120.55:2379 172.18.120.55:49988 ESTABLISHED 8072/etcd keepalive (5.13/0/0)
tcp 0 0 172.18.120.55:2379 172.18.120.56:52176 ESTABLISHED 8072/etcd keepalive (24.84/0/0)
tcp 0 0 172.18.120.55:51590 172.18.20.153:2379 ESTABLISHED 8804/kube-apiserver keepalive (1.42/0/0)
tcp 0 0 172.18.120.55:49878 172.18.120.55:2379 ESTABLISHED 8804/kube-apiserver keepalive (8.01/0/0)
tcp 0 0 172.18.120.55:49564 172.18.20.153:2379 ESTABLISHED 8804/kube-apiserver keepalive (12.87/0/0)
tcp 0 0 172.18.120.55:2379 172.18.120.56:50060 ESTABLISHED 8072/etcd keepalive (5.77/0/0)
tcp 0 0 172.18.120.55:2379 172.18.120.55:48138 ESTABLISHED 8072/etcd keepalive (19.08/0/0)
tcp 0 0 172.18.120.55:37618 172.18.20.153:2379 ESTABLISHED 8804/kube-apiserver keepalive (14.60/0/0)
...
keepalive (23.96/0/0):
表示当前 TCP 连接已启用 Keepalive 功能;
23.96
: 距离下次发送 Keepalive 探测包的剩余时间(单位为秒);
0
: 当前未检测到失败的探测包计数;
0
: 累积的重传探测次数。
6.2 抓包验证
使用 tcpdump 检查 Keepalive 探测包:
tcpdump -i eth0 tcp port <port> and tcp[tcpflags] == tcp-ack
6.3 调试日志
检查应用日志中是否存在与 Keepalive 探测相关的异常或断开信息。
参考
TCP Keepalive HOWTO(https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/index.html):此文档描述了 Linux 内核中的 TCP keepalive 实现,介绍了总体概念并指出了系统配置和软件开发。
原创 GrissomFI 原力注入