
在 Linux 服务器上执行 ss -ant,如果看到成百上千甚至更多的 ESTABLISHED 连接,第一反应往往是“连接泄漏”或“服务器快撑不住了”。但 ESTABLISHED 只表示 TCP 三次握手已经完成,双方仍维持连接状态,并不代表连接此刻一定在传输业务数据,也不能单凭数量判断故障。
WebSocket、HTTP/2、数据库连接池、消息队列消费者和反向代理都可能长期保持连接。真正需要回答的是:这些连接属于哪个进程、集中在哪个端口、是否持续收发数据、空闲多久,以及数量是否正在失控增长。
一、ESTABLISHED 连接多,哪些情况可能是正常的?
以下业务本身就会保留大量已建立连接:
WebSocket、在线客服、实时推送和长轮询;
HTTP/2 或 HTTP/3 网关后的持续会话;
Nginx、HAProxy、应用服务器之间的 Keep-Alive 连接;
数据库、Redis、消息队列等连接池;
微服务之间的 RPC 长连接;
高并发下载、视频传输或大文件上传。
如果连接数随在线用户或请求量同步变化,吞吐、延迟、错误率和文件描述符都处于正常范围,这些连接通常是业务容量的一部分。相反,如果请求量已经下降,连接数仍单向增长,或者某个进程的文件描述符不断逼近上限,就要重点排查空闲连接和连接泄漏。
二、先确认连接规模和变化趋势
查看 TCP 状态汇总:
ss -s cat /proc/net/sockstat
只查看已建立连接:
ss -ant state established
不要只记录一个瞬时数字。建议每隔一分钟采样一次,并同时记录业务 QPS、在线用户、CPU、内存、网络吞吐和错误率。若连接数持续增长而业务量没有同步增长,风险更高。
三、找出连接集中在哪个端口、IP 和进程
1. 按本地端口聚合
ss -ant state established | awk 'NR>1 {split($4,a,":"); print a[length(a)]}' | sort | uniq -c | sort -nr | head这能帮助判断连接主要来自 Web 服务端口、数据库端口,还是某个内部应用端口。IPv6 地址包含多个冒号,生产环境可结合实际输出使用更可靠的脚本或结构化监控处理。
2. 按远端地址聚合
ss -ant state established | awk 'NR>1 {print $5}' | sed 's/:[^:]*$//' | sort | uniq -c | sort -nr | head如果连接高度集中于少数来源,应结合负载均衡、NAT、代理出口和真实客户端 IP 判断。看到同一个地址不一定意味着单个用户,也可能是上游代理或 NAT 网关。
3. 关联到具体进程
sudo ss -antp state established sudo lsof -nP -iTCP -sTCP:ESTABLISHED
重点观察 PID、程序名、本地端口和对端地址。若同一进程的连接数不断增长,可进一步检查线程池、连接池、超时配置和异常路径是否正确释放套接字。
四、判断连接是活跃、空闲还是阻塞
ESTABLISHED 状态本身无法说明是否在传输数据。可以查看更详细的套接字信息:
sudo ss -iantop state established
结合发送队列、接收队列、重传、RTT、拥塞窗口和计时器判断。长期存在较大的 Send-Q 可能表示客户端读取过慢、网络拥塞或对端处理不及时;较大的 Recv-Q 可能表示应用没有及时读取已经到达的数据。
需要确认实际报文时,可在明确端口和范围后短时间抓包:
sudo tcpdump -ni any tcp port 443
抓包可能包含敏感信息,也会增加系统负担。生产环境应限制接口、端口、主机和抓取时长,并按照内部安全规范处理文件。
五、检查文件描述符是否接近上限
每个 TCP 套接字通常会占用文件描述符。连接很多时,应同时检查系统和进程限制:
ulimit -n cat /proc/<PID>/limits ls /proc/<PID>/fd | wc -l cat /proc/sys/fs/file-nr
如果进程已接近 Max open files,新连接、日志文件或其他文件操作都可能失败。提高上限只能增加容量,不能修复连接没有释放的应用缺陷。调整前应先确认连接增长原因、内存预算和服务管理器中的限制配置。
六、TCP Keepalive 为什么没有自动清理所有空闲连接?
Linux 提供以下常用参数:
sysctl net.ipv4.tcp_keepalive_time sysctl net.ipv4.tcp_keepalive_intvl sysctl net.ipv4.tcp_keepalive_probes
tcp_keepalive_time:连接空闲多久后开始发送探测;tcp_keepalive_intvl:探测之间的间隔;tcp_keepalive_probes:认定连接失效前最多发送多少次探测。
需要特别注意:这些内核参数只会影响已经启用 SO_KEEPALIVE 的套接字。应用没有为连接开启 TCP Keepalive,仅修改 sysctl 并不会让所有已建立连接自动获得探测机制。
应用层心跳与 TCP Keepalive 也不是同一件事。应用层心跳能够验证业务协议和应用进程是否仍在响应,并可携带会话信息;TCP Keepalive 主要用于识别连接路径或对端主机是否已经失效。WebSocket、数据库驱动和 RPC 框架通常还需要配置各自的 ping、心跳或空闲超时。
七、常见根因与对应处理
正常长连接容量不足
如果连接与活跃用户一致,应按容量问题处理:核对进程文件描述符、内存占用、负载均衡连接能力和连接池上限,并通过扩容或分片分担连接。
应用连接泄漏
检查异常、超时和取消请求路径是否都会执行关闭操作。数据库或 HTTP 客户端连接池要设置合理的最大连接数、最大空闲连接数、空闲回收时间和连接生命周期。修复应落在应用代码或连接池配置上,而不是依赖系统强制清理。
慢客户端或网络质量差
结合 Send-Q、重传和应用响应时间确认。可以设置合理的读写超时、请求体限制和并发限制,但不要为了快速降低连接数而盲目调低超时,以免误断正常的大文件传输或弱网用户。
中间设备空闲超时不一致
负载均衡、NAT、防火墙和代理可能有不同的空闲超时。应用层心跳间隔通常应短于路径中最短的空闲超时,并留出安全余量。具体数值要根据当前设备文档、业务特性和实际网络测试确定。
连接跟踪表压力
使用 Netfilter 的服务器或网关还可检查:
sudo conntrack -S sysctl net.netfilter.nf_conntrack_count sysctl net.netfilter.nf_conntrack_max
如果系统没有安装 conntrack 工具,或者主机不承担相关网络角色,命令可能不可用。连接跟踪表与应用套接字不是同一个维度,需要结合网络拓扑分析。
八、推荐的排查顺序
确认连接总量、增长速度和出现时间;
对照 QPS、在线用户、延迟、错误率和网络吞吐;
按本地端口和远端地址聚合;
关联 PID,找出主要进程和服务;
检查 Send-Q、Recv-Q、重传和套接字计时器;
检查进程文件描述符及连接池上限;
核对应用超时、心跳、SO_KEEPALIVE 与内核参数;
核对负载均衡、NAT、防火墙的空闲超时;
必要时进行受控抓包或应用级追踪。
九、修改参数前如何降低风险?
不要直接在全部服务器上修改 Keepalive、连接池或超时。先保存当前参数和监控基线,在少量实例上灰度变更,持续观察连接数、重连率、错误率、P95/P99 延迟、CPU、内存和文件描述符。准备可执行的回滚值,并确认配置能在重启后按预期生效。
如果降低空闲超时后连接数下降,却同时出现重连激增、登录掉线或数据库连接抖动,这通常不是成功修复,而是把压力转移到了握手和重建连接阶段。
十、修复后如何验证?
连接数是否随真实业务量稳定变化,不再无界增长;
进程文件描述符是否回到安全水位;
连接池等待时间、超时和拒绝数量是否下降;
重连率、握手量和错误率是否没有异常上升;
弱网客户端、长任务和大文件传输是否仍然正常;
重启或滚动发布后配置是否仍然有效。
常见问题
ESTABLISHED 连接多就是被攻击了吗?
不是。正常长连接和高并发业务也会产生大量已建立连接。攻击判断需要结合来源分布、请求行为、带宽、错误率、认证日志和业务基线。
可以直接 kill 掉这些连接吗?
不建议把批量断开作为常规修复。它会中断正常用户,并可能引发集中重连。应先定位进程、业务类型和根因;紧急处置也要控制范围并准备回滚。
把 tcp_keepalive_time 调得很小可以吗?
数值过小会增加探测流量和误判风险,而且应用未启用 SO_KEEPALIVE 时不会按预期生效。应根据业务空闲周期和中间设备超时灰度调整。
为什么服务重启后连接数马上又上来了?
如果连接来自正常客户端或自动重连机制,重启只会暂时清空状态。若根因是容量不足、泄漏、超时不匹配或客户端行为,连接仍会重新建立。
结论
Linux 服务器出现大量 ESTABLISHED 连接时,正确做法不是先调内核参数,而是先把连接与端口、来源、进程、业务流量和文件描述符对应起来。确认是正常长连接后做容量规划;确认是空闲连接、泄漏或超时不匹配后,再分别从应用、连接池、Keepalive 和网络设备配置入手。任何全局参数变更都应有基线、灰度、监控和回滚。
参考资料
RFC 9293:Transmission Control Protocol (TCP),核查日期:2026-09-04
Linux Kernel Documentation:IP Sysctl,核查日期:2026-09-04
Linux man-pages:ss(8),核查日期:2026-09-04
Linux man-pages:tcp(7),核查日期:2026-09-04