服务器长连接资源释放优化教程指南
长连接为什么会占着资源不放
很多刚接触服务器运维的朋友会遇到一个问题:服务器明明没什么人在用,但内存、文件描述符却居高不下。
这很大概率是长连接没有及时释放导致的。
长连接一旦建立,如果客户端不主动断开,服务器侧会一直保留该连接及对应的资源。
时间一长,堆积的空闲连接就会拖慢整个系统。
动手优化前,先确认你的服务器环境
在执行优化之前,需要先知道当前服务器的连接现状和操作系统版本。
- 查看当前所有连接(包括长连接) 在终端输入:
netstat -ant | wc -l
这个命令会统计所有 TCP 连接的总数。
如果数字很大(比如几万),说明连接数可能需要优化。
- 确认操作系统版本 输入:
cat /etc/os-release
Ubuntu、CentOS、Debian 的操作基本一致,但个别路径可能不同,我会在文中特殊说明。
- 备份重要配置 修改系统参数前,先备份
/etc/sysctl.conf(如果是修改内核参数),或者备份你的应用配置文件。
长连接资源释放优化的核心步骤
这里我会从系统层面和应用层面两个维度来讲,两个都做效果最好。
1. 调整内核参数,让系统主动关闭空闲连接
Linux 内核提供了 tcp_keepalive 系列参数来控制连接保活和超时回收。
修改 /etc/sysctl.conf 文件(没有则新建),加入下面几行:
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
tcp_keepalive_time:连接闲置多少秒后开始发送探测包,这里设为 600 秒(10 分钟)。tcp_keepalive_intvl:每次探测的间隔,30 秒。tcp_keepalive_probes:探测几次无响应就断开连接,3 次。
保存后执行 sysctl -p 使配置生效。
验证方法:用 sysctl net.ipv4.tcp_keepalive_time 查看修改后的值。
2. 调整应用层的连接池参数
Nginx、Tomcat、MySQL、Redis 等软件都有自己的连接池或超时设置。
这里以 Nginx 反向代理 为例:
打开 Nginx 配置文件(通常位于 /etc/nginx/nginx.conf 或站点配置里),在 http 段或 server 段中添加:
proxy_http_version 1.1;
proxy_set_header Connection "";
keepalive_timeout 60;
keepalive_requests 1000;
keepalive_timeout:长连接超时时间,单位秒,60 秒后自动断开。keepalive_requests:一个长连接最多处理 1000 个请求后自动断开,防止无限复用导致资源泄露。
保存后重启 Nginx:nginx -s reload。
如果是 MySQL 数据库,可以在 my.cnf 中调整 wait_timeout 和 interactive_timeout:
[mysqld]
wait_timeout = 300
interactive_timeout = 300
3. 使用工具清理已卡死的连接(应急方案)
如果已经有一些连接处于 CLOSE_WAIT 或 FIN_WAIT2 状态且无法自动回收,可以用 tcpkill 或 ss 命令强制断开:
ss -tan | grep CLOSE_WAIT
找到目标连接的 IP 和端口后,使用 tcpkill(需安装 dsniff 包)断开:
tcpkill -i eth0 host 192.168.1.100 and port 8080
注意:强制断开会影响正在进行的请求,尽量在业务低峰期操作。
这些坑我替你们踩过了
- 不要随意把 keepalive_time 设得太短(比如 30 秒)。频繁建立新连接会加重 CPU 和网络开销,反而降低性能。一般建议 5~15 分钟。
- 修改内核参数后一定要测试应用是否受影响。可以写一个小脚本模拟长连接,观察服务是否会因为断连而报错。
- Nginx 的 keepalive_requests 不能设成 0(0 表示不限制),这会导致连接永远不主动断开,风险很大。
- 如果服务器上有多个应用共享同一个端口,调整系统级的 tcp_keepalive 参数会影响到所有应用,需要评估兼容性。
如何确认优化生效了
执行优化后,过一段时间(比如半小时)再次检查连接状态:
netstat -ant | grep ESTAB | wc -l
正常情况下连接数会明显下降(取决于你的服务并发)。
同时可以用 vmstat 或 top 观察内存占用是否减少。
如果想看具体哪些连接被关闭了,可以开启内核日志:
dmesg -T | grep -i "TCP: time wait bucket"
没有输出说明没有异常关闭。
最后,建议在正式环境变更前,先在测试环境完整跑一遍上面的步骤,确保不会影响业务。
如果你在操作中遇到报错,欢迎在评论区贴出命令输出,我会帮你排查。