linux 下端口close_wait 过多

本文针对Linux环境下出现大量CLOSE_WAIT状态的问题进行了深入分析,并提供了两种解决方案:一是通过设置超时来解决,二是通过调整系统参数来规避。同时介绍了如何检查及调整相关参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

linux 下端口close_wait 过多

 

情景描述:系统产生大量“Too many open files”
原因分析:在服务器与客户端通信过程中,因服务器发生了socket未关导致的closed_wait发生,致使监听port打开的句柄数到了1024个,且均处于close_wait的状态,最终造成配置的port被占满出现“Too many open files”,无法再进行通信。
close_wait状态出现的原因是被动关闭方未关闭socket造成,如附件图所示:

解决办法:有两种措施可行
一、解决:
原因是因为调用ServerSocket类的accept()方法和Socket输入流的read()方法时会引起线程阻塞,所以应该用setSoTimeout()方法设置超时(缺省的设置是0,即超时永远不会发生);超时的判断是累计式的,一次设置后,每次调用引起的阻塞时间都从该值中扣除,直至另一次超时设置或有超时异常抛出。
比如,某种服务需要三次调用read(),超时设置为1分钟,那么如果某次服务三次read()调用的总时间超过1分钟就会有异常抛出,如果要在同一个Socket上反复进行这种服务,就要在每次服务之前设置一次超时。
二、规避:
调整系统参数,包括句柄相关参数和TCP/IP的参数;

注意:
/proc/sys/fs/file-max 是整个系统可以打开的文件数的限制,由sysctl.conf控制;
ulimit修改的是当前shell和它的子进程可以打开的文件数的限制,由limits.conf控制;
lsof是列出系统所占用的资源,但是这些资源不一定会占用打开文件号的;比如:共享内存,信号量,消息队列,内存映射等,虽然占用了这些资源,但不占用打开文件号;
因此,需要调整的是当前用户的子进程打开的文件数的限制,即limits.conf文件的配置;
如果cat /proc/sys/fs/file-max值为65536或甚至更大,不需要修改该值;
若ulimit -a ;其open files参数的值小于4096(默认是1024), 则采用如下方法修改open files参数值为8192;方法如下:
1.使用root登陆,修改文件/etc/security/limits.conf
vi /etc/security/limits.conf 添加
xxx - nofile 8192
xxx 是一个用户,如果是想所有用户生效的话换成 * ,设置的数值与硬件配置有关,别设置太大了。
#<domain>      <type>     <item>         <value>

*         soft    nofile    8192
*         hard    nofile    8192

#所有的用户每个进程可以使用8192个文件描述符。
2.使这些限制生效
确定文件/etc/pam.d/login 和/etc/pam.d/sshd包含如下行:
session required pam_limits.so
然后用户重新登陆一下即可生效。
3. 在bash下可以使用ulimit -a 参看是否已经修改:

一、 修改方法:(暂时生效,重新启动服务器后,会还原成默认值)
sysctl -w net.ipv4.tcp_keepalive_time=600  
sysctl -w net.ipv4.tcp_keepalive_probes=2
sysctl -w net.ipv4.tcp_keepalive_intvl=2

注意:Linux的内核参数调整的是否合理要注意观察,看业务高峰时候效果如何。

二、 若做如上修改后,可起作用;则做如下修改以便永久生效。
vi /etc/sysctl.conf

若配置文件中不存在如下信息,则添加:
net.ipv4.tcp_keepalive_time = 1800
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 15

编辑完 /etc/sysctl.conf,要重启network 才会生效
/etc/rc.d/init.d/network restart
然后,执行sysctl命令使修改生效,基本上就算完成了。

------------------------------------------------------------
修改原因:

当客户端因为某种原因先于服务端发出了FIN信号,就会导致服务端被动关闭,若服务端不主动关闭socket发FIN给Client,此时服务端Socket会处于CLOSE_WAIT状态(而不是LAST_ACK状态)。通常来说,一个CLOSE_WAIT会维持至少2个小时的时间(系统默认超时时间的是7200秒,也就是2小时)。如果服务端程序因某个原因导致系统造成一堆CLOSE_WAIT消耗资源,那么通常是等不到释放那一刻,系统就已崩溃。因此,解决这个问题的方法还可以通过修改TCP/IP的参数来缩短这个时间,于是修改tcp_keepalive_*系列参数:
tcp_keepalive_time:
/proc/sys/net/ipv4/tcp_keepalive_time
INTEGER,默认值是7200(2小时)
当keepalive打开的情况下,TCP发送keepalive消息的频率。建议修改值为1800秒。

tcp_keepalive_probes:INTEGER
/proc/sys/net/ipv4/tcp_keepalive_probes
INTEGER,默认值是9
TCP发送keepalive探测以确定该连接已经断开的次数。(注意:保持连接仅在SO_KEEPALIVE套接字选项被打开是才发送.次数默认不需要修改,当然根据情形也可以适当地缩短此值.设置为5比较合适)

tcp_keepalive_intvl:INTEGER
/proc/sys/net/ipv4/tcp_keepalive_intvl
INTEGER,默认值为75
当探测没有确认时,重新发送探测的频度。探测消息发送的频率(在认定连接失效之前,发送多少个TCP的keepalive探测包)。乘以tcp_keepalive_probes就得到对于从开始探测以来没有响应的连接杀除的时间。默认值为75秒,也就是没有活动的连接将在大约11分钟以后将被丢弃。(对于普通应用来说,这个值有一些偏大,可以根据需要改小.特别是web类服务器需要改小该值,15是个比较合适的值)

【检测办法】
1. 系统不再出现“Too many open files”报错现象。

2. 处于TIME_WAIT状态的sockets不会激长。

在 Linux 上可用以下语句看了一下服务器的TCP状态(连接状态数量统计):

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

返回结果范例如下:

ESTABLISHED 1423
FIN_WAIT1 1
FIN_WAIT2 262
SYN_SENT 1
TIME_WAIT 962
<think>好的,我需要解决用户关于Linux服务器上出现大量CLOSE_WAIT状态的问题。首先,我得回顾一下TCP连接的状态转换过程,尤其是CLOSE_WAIT和TIME_WAIT的区别。根据引用[5],CLOSE_WAIT出现在被动关闭连接的一方,也就是服务器在接收到客户端的FIN报文后进入这个状态,等待应用程序关闭连接。而TIME_WAIT则是主动关闭连接的一方在发送最后一个ACK后进入的状态,用来处理可能延迟的报文。 用户的问题是服务器上有大量CLOSE_WAIT,这说明服务器端的应用程序没有正确关闭连接。引用[4]提到,检测到对端关闭后,node.js会自动关闭本端socket,但如果应用程序没有执行close操作,就会导致CLOSE_WAIT堆积。因此,根本原因可能在于代码中没有正确释放连接资源。 接下来,我需要整理解决方案的步骤。首先,应该检查应用程序代码,确保所有socket连接在使用后正确关闭,特别是数据库连接、文件句柄等资源。引用[3]指出服务端使用短连接时,主动关闭连接会导致TIME_WAIT,但这里的问题不同,是CLOSE_WAIT,所以重点在代码层面的资源释放。 然后,查看系统参数,虽然引用[2]提到TIME_WAIT可以通过优化服务器参数解决,但CLOSE_WAIT更多是应用程序的问题,系统参数调整可能有限,但可以检查文件描述符限制,比如ulimit -n的设置,避免资源耗尽。 接下来,网络排查。使用netstat或ss命令查看具体连接情况,确认是哪些进程导致的CLOSE_WAIT,结合lsof或/proc文件系统定位到具体进程和代码位置。例如,使用netstat -ae | grep CLOSE_WAIT,类似引用[1]中的命令,但替换为CLOSE_WAIT状态。 另外,引用[3]提到服务端主动关闭连接导致TIME_WAIT,但这里的情况是服务端被动关闭,所以需要确保应用程序在收到FIN后及时close。如果是HTTP服务,检查是否使用了Keep-Alive,适当调整超时时间,避免连接长时间未关闭。 可能还需要使用压力测试工具模拟高并发场景,观察CLOSE_WAIT的增长情况,验证修复措施是否有效。同时,监控工具如Prometheus或Grafana可以帮助实时监控连接状态变化。 最后,总结解决方案步骤,从代码检查、资源释放、系统参数、网络排查到监控优化,逐步排除问题。需要提醒用户,CLOSE_WAIT问题通常由应用程序未正确关闭连接引起,与TIME_WAIT不同,后者更多是系统参数调整的问题,如引用[2]和[3]所述。 需要确保回答结构清晰,分步骤说明,并引用相关参考资料。同时,生成的相关问题要围绕TCP状态、区别、其他状态的解决方案等。</think>### 处理Linux服务器中大量CLOSE_WAIT连接的解决方案 #### 1. **理解CLOSE_WAIT状态的本质** CLOSE_WAIT是TCP连接关闭过程中的一个中间状态,表示**被动关闭方(通常是服务器)已收到主动关闭方(客户端)的FIN报文**,但尚未关闭本端连接[^5]。大量CLOSE_WAIT连接的堆积表明**应用程序未正确关闭socket连接**,导致资源无法释放[^4]。 --- #### 2. **排查与解决步骤** ##### **步骤1:检查应用程序代码** - **核心问题**:未显式调用`close()`方法释放连接。 - **常见场景**: - 数据库连接未关闭 - HTTP请求未关闭响应流 - 文件句柄泄漏 - **代码修复示例**(以Python为例): ```python # 错误示例:未关闭socket def handle_request(client_socket): data = client_socket.recv(1024) # 处理请求但未关闭连接 # 正确示例:显式关闭连接 def handle_request(client_socket): try: data = client_socket.recv(1024) # 处理请求 finally: client_socket.close() # 确保关闭 ``` ##### **步骤2:检查系统资源限制** - 使用命令查看当前进程打开的文件描述符数量: ```bash lsof -p <进程PID> | wc -l ``` - 调整系统文件描述符限制(临时生效): ```bash ulimit -n 65535 # 修改为更高限制 ``` ##### **步骤3:网络连接分析** - 使用`netstat`或`ss`命令定位问题: ```bash netstat -antop | grep CLOSE_WAIT # 查看所有CLOSE_WAIT连接 ss -s | grep CLOSE_WAIT # 更高效的统计方式 ``` - 结合`lsof`追踪具体进程: ```bash lsof -i :<端口号> # 查看占用端口的进程 ``` ##### **步骤4:优化连接管理策略** - **HTTP服务场景**: - 禁用不必要的Keep-Alive:减少长连接占用时间。 - 设置合理的超时时间(如Nginx配置): ```nginx keepalive_timeout 5; # 5秒后关闭空闲连接 ``` --- #### 3. **对比CLOSE_WAIT与TIME_WAIT的差异** | 状态 | 触发方 | 原因 | 解决方案 | |------------|----------|-------------------------------|------------------------------| | CLOSE_WAIT | 被动关闭 | 应用程序未关闭连接 | 修复代码逻辑 | | TIME_WAIT | 主动关闭 | 系统等待延迟报文 | 调整`tcp_tw_reuse`等内核参数[^3] | --- #### 4. **监控与验证** - **实时监控命令**: ```bash watch -n 1 "netstat -ant | grep CLOSE_WAIT | wc -l" # 每秒统计CLOSE_WAIT数量 ``` - **验证修复效果**: - 重启应用后观察CLOSE_WAIT是否减少。 - 使用压力测试工具(如`ab`、`wrk`)模拟高并发场景。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值