连接建着却没有数据
排查连接数时经常看到大量 ESTABLISHED,但实际没有业务流量。这种连接有三类:连接池里的空闲连接(正常)、中间设备已老化而两端并不知情的「假连接」(故障根源)、以及应用线程卡死占住的连接。判据很直接:用 ss -tino 看发送与接收队列是否都为 0,只剩 keepalive 定时器在跳动,说明这条连接长时间没有数据流动。
基本信息
| 适用平台 | Linux(ss -tino 显示队列与定时器信息) |
|---|---|
| 关键判据 | Send-Q 与 Recv-Q 均为 0,仅有 keepalive 定时器 |
| 典型成因 | NAT/负载均衡的空闲超时短于应用心跳间隔,连接被中间设备静默丢弃 |
| 处置方向 | 启用 TCP keepalive 或应用层心跳,把探测间隔压到中间设备老化时间以内 |
| 协议依据 | RFC 1122 定义的 TCP Keep-Alive 机制 |
典型使用场景
- 服务周期性报 read timeout 但抓包看不到任何报文:怀疑假连接
- 连接池利用率低但连接数很高:确认是否存在大量空闲连接
- 云环境中出现规律性「假死」:核对 NAT 网关的空闲超时与应用心跳间隔
- 数据库连接异常断开:确认中间设备或数据库侧的空闲回收策略
- 容量评估:区分有效活跃连接与空闲连接,避免按总数扩容
判据与观察
判据与观察
ss -tino state established '( dport = :3306 )' | head # 看队列与定时器
ss -tan state established | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head # 按对端分布
watch -n10 "ss -Htn state established | wc -l" # 观察总数是否随时间平滑下降
# keepalive 相关内核参数:探测前空闲时间、探测间隔、探测次数
sysctl net.ipv4.tcp_keepalive_time net.ipv4.tcp_keepalive_intvl net.ipv4.tcp_keepalive_probes
# 应用侧确认心跳与连接池 idle 时间配置形态与判读
| 形态 | 含义 | 处置方向 |
|---|---|---|
| 队列为 0 且长时间无数据 | 空闲连接或假连接 | 核对中间设备超时与心跳间隔 |
| 应用报超时但抓不到报文 | 典型假连接 | 缩短心跳间隔或启用 TCP keepalive |
| 连接数缓慢下降 | 连接池正常回收 | 属正常行为,无需干预 |
| 连接数只增不减 | 疑似连接泄漏 | 检查代码是否正确释放连接 |
| 重连后立即恢复 | 中间设备已丢弃该连接 | 定位中间设备的空闲超时值 |
云上 NAT 网关的空闲超时是常见坑:应用连接池的空闲时间若大于它,就会周期性出现「假死」。核对两者数值,把心跳间隔设得比中间设备超时更短。