linux端口被占用,netstat查看无进程号,端口状态一直停留在FIN_WAIT1以及CLOSE_WAIT状态

环境信息:

CentOS 6.5

现象:

同事启动程序发现端口被占用,netstat查看之后发现如下现象:

发现端口处于FIN_WAIT1状态以及CLOSE_WAIT状态,无法释放

问题分析:

FIN_WAIT1以及CLOSE_WAIT状态的原理以及产生的原因大家自行baidu,下面就说下怎么解决上述问题,释放端口

FIN_WAIT1:

1、sysctl -a |grep tcp_max_orph(记下 net.ipv4.tcp_max_orphans  的值  第三步需要赋给orig_orphans)  

2、sysctl -w net.ipv4.tcp_max_orphans=0   然后等待FIN_WAIT1的消失,可以用 netstat -np|grep 9080  反复查看,直到没有任何条目

3、sysctl -w net.ipv4.tcp_max_orphans=$orig_orphans

执行完毕查看:

CLOSE_WAIT:

当客户端因为某种原因先于服务端发出了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是个比较合适的值) 

 

修改方法:

一、 命令修改:(暂时生效,重新启动服务器后,会还原成默认值) 
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命令使修改生效,基本上就算完成了。

问题总结:

       上述操作完事后,常规的问题应该就能解决了,但是在我的场景中未能解决,CLOSE_WAIT进程未能关闭,因为netstat命令中第二列的REC-Q也就是接收队列不为0,有积压,导致CLOSE_WAIT未能被自动关闭,经排查,发现该端口对应的进程都成为了僵尸进程导致端口无法释放。

      僵尸进程又分为僵尸进程和孤儿进程,区别是通过ps命令查看僵尸进程的PPID是否为空,不为空是僵尸进程,为空是孤儿进程。如果是僵尸进程,处理方式参照我之前的博客https://blog.youkuaiyun.com/microGP/article/details/81509335;如果是孤儿进程,一般情况下操作系统在一定时间内自己就回收了,稍等即可

<think>好的,我现在需要解决用户提到的Linux系统中TIME_WAIT状态过多导致Java程序出现NoRouteToHostException的问题。首先,我应该回忆一下相关的网络知识,特别是关于TCP连接的状态转换。TIME_WAIT状态出现在主动关闭连接的一方,也就是当TCP连接正常关闭时,会进入这个状态,持续2MSL(Maximum Segment Lifetime)时间,通常是60秒。这是为了确保最后一个ACK报文能够到达对方,并处理可能延迟到达的数据包,防止旧连接的数据干扰新连接。 用户的问题是由于系统中存在大量的TIME_WAIT连接,导致本地端口被耗尽,无法分配新的端口,从而引发NoRouteToHostException。这时候,Java应用程序在尝试建立新的Socket连接时,无法获取可用的本地端口,因此报错。 接下来,我需要考虑如何减少TIME_WAIT的数量或者优化端口的使用。根据引用中的资料,特别是引用[3]提到的修改本地端口范围,可能需要调整sysctl.conf中的参数。此外,可能还需要调整其他相关的内核参数,比如开启端口重用,或者调整TIME_WAIT的超时时间。 首先,调整本地端口范围。默认的端口范围可能较小,导致在高并发下快速耗尽。将net.ipv4.ip_local_port_range设置为更大的范围,如10000到65000,这样可以提供更多的可用端口,延缓耗尽的时间。 其次,开启端口重用(SO_REUSEADDR和SO_REUSEPORT),允许新的连接重用处于TIME_WAIT状态端口。这可以通过设置net.ipv4.tcp_tw_reuse为1来实现。需要注意的是,这个参数需要和tcp_timestamps一起启用,确保时间戳的支持,以避免安全问题。 另外,调整TIME_WAIT的超时时间也是一个可能的解决方案,但不太推荐,因为这可能影响TCP的可靠性。不过,如果有必要,可以设置net.ipv4.tcp_fin_timeout为一个较小的值,但这通常不如调整端口重用有效。 还有,增加最大文件描述符数也可能有帮助,特别是在高并发场景下,确保系统可以处理更多的连接。这需要调整ulimit或相关的文件描述符限制。 然后,需要考虑Java程序本身的优化,比如使用连接池来复用连接,减少频繁创建和关闭连接的情况。同时,检查代码中是否存在未正确关闭连接的情况,确保每次连接使用后都被正确释放。 此外,可能还需要调整TCP的keepalive参数,减少不必要的连接保持时间,从而更快地释放资源。不过,这可能影响长连接的场景,需要根据具体情况权衡。 最后,实施这些修改后,需要通过sysctl -p命令使配置生效,并重启受影响的Java应用。之后,监控系统的网络状态,使用netstat或ss命令查看TIME_WAIT的数量是否减少,以及应用程序是否恢复正常。 需要验证每个步骤的正确性,比如确认内核参数的作用,避免设置错误导致其他问题。例如,调整tcp_max_tw_buckets可以限制TIME_WAIT的数量,但设置过低可能导致连接过早被关闭。因此,需要根据实际负载和系统资源进行合理配置。 总结来说,解决方案应围绕调整内核参数、优化端口使用、改进应用程序的连接管理三个方面展开。同时,引用中提到的修改本地端口范围和启用端口重用是关键步骤,结合其他优化措施,可以有效缓解问题。</think>### 解决方案:Linux系统中TIME_WAIT过多导致`NoRouteToHostException`的解决方法 当Linux系统中存在大量`TIME_WAIT`状态的TCP连接时,会导致本地端口耗尽,Java程序无法分配新端口,从而抛出`java.net.NoRouteToHostException`。以下是逐步解决方案: --- #### **1. 调整本地端口范围** 通过扩大可用本地端口范围,延缓端口耗尽的速度: ```bash # 编辑系统参数配置文件 sudo vi /etc/sysctl.conf # 添加或修改以下参数(10000~65000为端口范围) net.ipv4.ip_local_port_range = 10000 65000 # 保存后生效配置 sudo sysctl -p ``` 此修改允许系统使用更多端口,减少因端口不足导致的错误[^3]。 --- #### **2. 启用端口快速重用** 允许内核重用处于`TIME_WAIT`状态端口(需确保时间戳功能开启): ```bash sudo vi /etc/sysctl.conf # 添加以下参数 net.ipv4.tcp_tw_reuse = 1 # 允许重用TIME_WAIT端口 net.ipv4.tcp_timestamps = 1 # 启用时间戳支持 # 生效配置 sudo sysctl -p ``` 此配置可减少`TIME_WAIT`状态的持续时间。 --- #### **3. 调整TIME_WAIT相关参数** 限制系统中`TIME_WAIT`连接的最大数量: ```bash sudo vi /etc/sysctl.conf # 添加以下参数 net.ipv4.tcp_max_tw_buckets = 200000 # 增加TIME_WAIT连接的最大桶数 # 生效配置 sudo sysctl -p ``` --- #### **4. 优化应用程序行为** - **使用连接池**:在Java代码中使用连接池(如Apache HttpClient、HikariCP等),避免频繁创建/关闭短连接。 - **关闭连接时使用`Connection: close`**:确保HTTP请求头中明确关闭连接,避免长连接积累。 - **检查代码泄漏**:确保所有Socket或HTTP连接正确调用`close()`方法。 --- #### **5. 监控与验证** - **查看当前TIME_WAIT数量**: ```bash ss -s | grep TIME-WAIT ``` - **检查端口使用情况**: ```bash netstat -an | awk '/tcp/ {print $6}' | sort | uniq -c ``` --- #### **6. 其他可选优化** - **减少`FIN_WAIT2`时间**(默认60秒): ```bash net.ipv4.tcp_fin_timeout = 30 ``` - **增加文件描述符限制**: ```bash # 修改/etc/security/limits.conf * soft nofile 65535 * hard nofile 65535 ``` --- ### 总结 通过调整内核参数(如端口范围、TIME_WAIT重用)和优化应用程序设计(如连接池),可有效缓解因`TIME_WAIT`过多导致的`NoRouteToHostException`问题。建议优先使用参数`net.ipv4.tcp_tw_reuse`和`net.ipv4.ip_local_port_range`,并结合代码级优化。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值