TCP Keepalive 是什么
TCP 保活是一组探测机制:连接空闲到一定时间后,内核向对端发送不带数据的探测报文,连续多次无响应就判定连接已死并通知应用。三个全局参数分别控制首个探测的等待时间、探测间隔和失败判定次数,默认组合约需 2 小时 11 分钟才会发现对端失联。它只在应用对该套接字开启 SO_KEEPALIVE 后才会生效,因此与 HTTP 层的 keep-alive、Nginx 的 keepalive_timeout 是完全不同的东西。
基本信息
| tcp_keepalive_time | 连接空闲多久后发出首个探测,默认 7200 秒 |
|---|---|
| tcp_keepalive_intvl | 相邻探测的间隔,默认 75 秒 |
| tcp_keepalive_probes | 连续失败多少次判定断开,默认 9 次 |
| 启用条件 | 应用需对套接字设置 SO_KEEPALIVE,否则参数形同虚设 |
| 单连接覆盖 | 应用可用 TCP_KEEPIDLE、TCP_KEEPINTVL、TCP_KEEPCNT 单独设定 |
| 观测命令 | ss -o 查看连接计时器,含 keepalive 剩余时间 |
典型使用场景
- 穿越 NAT 与防火墙的长连接:中间设备空闲回收后连接被静默丢弃,靠保活及早发现并重建
- 数据库连接池与消息队列客户端:链路抖动后连接假活,业务请求挂住直到超时才失败
- 微服务之间的长连接:希望故障节点的连接尽快被剔除,而不是等到业务超时
- 负载均衡后端健康判断:保活能让客户端及时感知后端下线,缩短故障切换时间
- 排查连接黑洞:应用报读超时而底层无任何 RST,用 ss -o 看保活计时器确认是否已检测到异常
查看与调整
查看与调整
sysctl net.ipv4.tcp_keepalive_time net.ipv4.tcp_keepalive_intvl net.ipv4.tcp_keepalive_probes # 读三参数
sysctl -w net.ipv4.tcp_keepalive_time=600 # 10 分钟空闲后开始探测
sysctl -w net.ipv4.tcp_keepalive_intvl=30 # 每次探测间隔 30 秒
sysctl -w net.ipv4.tcp_keepalive_probes=3 # 3 次无响应即判定断开
ss -o state established '( dport = :3306 )' # timer:(keepalive,剩余时间) 观察保活状态
ss -o state established | head # 查看全部已建立连接的计时器落盘与回读
落盘与回读
# /etc/sysctl.d/99-keepalive.conf
net.ipv4.tcp_keepalive_time = 600 # 首个保活探测前的空闲时间
net.ipv4.tcp_keepalive_intvl = 30 # 探测间隔
net.ipv4.tcp_keepalive_probes = 3 # 失败判定次数参数组合读法
| 参数 | 默认值 | 调整方向 |
|---|---|---|
| tcp_keepalive_time | 7200 秒 | 按链路空闲回收时间下调,需小于中间设备的回收阈值 |
| tcp_keepalive_intvl | 75 秒 | 故障发现要求快时降到 15~30 秒 |
| tcp_keepalive_probes | 9 次 | 内网稳定可降到 3 次,配合间隔缩短判定时间 |
| 默认合计 | 约 2 小时 11 分 | 远超多数 NAT 空闲回收时间,长连接业务通常需要调整 |
中间设备的空闲回收时间通常只有数百秒量级,不同厂商与型号取值不同,因此保活探测间隔应明显小于该值,让探测在连接被静默回收前发生。有条件的场景建议在应用层加心跳,语义比 TCP 保活更可控。
这是全局参数,改小会让机器上所有开启保活的连接(数据库连接池、服务间长连接、监控上报)都更频繁发探测包。在有数万长连接的节点上,探测流量与唤醒次数会同步上升,调整前先评估连接规模。
保活只能发现链路已断,无法判断对端进程是否健康。若需要业务级存活判断,应由应用心跳或健康检查承担;把保活当作健康检查会漏掉对端进程僵死但仍能回 ACK 的情况。
云主机与容器场景要留意层级:保活探测由客户端内核发出,若路径上存在 SNAT 网关,网关自身的空闲回收时间可能先到,连接在探测发出前就已被丢弃。此时需要同时核对网关侧的会话超时配置。