必须在应用层调用setsockopt启用SO_KEEPALIVE,否则系统级tcp_keepalive_time等参数完全无效;多数默认工具(如curl、Python socket)未开启该选项,仅修改sysctl配置无法触发探测。

系统级 TCP Keepalive 参数改了也没用——除非你明确知道哪些连接真需要它,且不介意所有启用 SO_KEEPALIVE 的连接(包括 SSH、监控探针、短连接)都受同一套规则约束。
为什么直接改 /etc/sysctl.conf 很可能白忙活
全局参数只影响那些已启用 SO_KEEPALIVE 选项的 socket,而大多数应用(比如 curl、wget、默认 Python socket)根本没开这个选项。改了 tcp_keepalive_time 等值,对它们完全无效。
-
ss -tn显示 ESTABLISHED 并不代表连接通;它只反映内核 TCP 状态,不校验链路是否真实可达 - 默认
tcp_keepalive_time=7200(2 小时),但多数 NAT 设备 5–30 分钟就清连接表,首探永远发不出去 - 改大参数(如设成 3600)反而让故障感知更慢;改小(如 300)又可能对短连接造成无谓探测压力
sysctl -w 临时改参的适用场景
仅适合快速验证或调试:确认某组参数在当前网络环境下能否触发探测、是否被中间设备拦截。不能替代应用层配置。
- 必须三者一起调:
sudo sysctl -w net.ipv4.tcp_keepalive_time=600、sudo sysctl -w net.ipv4.tcp_keepalive_intvl=30、sudo sysctl -w net.ipv4.tcp_keepalive_probes=3 - 改完立刻生效,但重启即失效;别只改一个参数,否则行为不可预测(比如只调
time不调intvl,探测间隔仍为默认 75 秒) - 验证是否写入成功:
cat /proc/sys/net/ipv4/tcp_keepalive_time,别信命令返回“success”就当真
持久化必须走 /etc/sysctl.conf + sysctl -p
写进配置文件不是终点,sysctl -p 才真正加载。漏这步,重启后还是默认值。
- 编辑时追加三行,格式严格:
net.ipv4.tcp_keepalive_time = 600(等号前后有空格,无引号,无注释混在同一行) -
sysctl -p若报错,常见原因是某行格式不对或参数名拼错(比如写成tcp_keep_alive_time) - 改完建议跑一次
sudo sysctl --system,它会重新加载所有 sysctl 配置片段,比单跑-p更稳妥
真正起效的前提:应用得主动开 SO_KEEPALIVE
内核参数只是“规则手册”,应用不调 setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)),规则就永远不会被执行。
- Nginx 需在
listen指令里显式加so_keepalive=on或so_keepalive=30s:30s:3 - Go 的
net.Conn默认不开,得用SetKeepAlive和SetKeepAlivePeriod - Java Netty 要在
ChannelOption.SO_KEEPALIVE设为 true,且底层 OS 支持 TCP 层定制才可调 idle/intvl
参数调得再细,只要应用没调 setsockopt 启用开关,就等于没装探测器——图纸画得再好,没人按按钮,什么都不会发生。


















