阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

记一次大量CLOSE_WAIT的解决方案

161次阅读
没有评论

共计 1897 个字符,预计需要花费 5 分钟才能阅读完成。

问题:

Cannot send, channel has already failed: tcp://ip:61616
Javax.jms.JMSException: Cannot send, channel has already failed: tcp://ip:61616

应用连不上 mq

解决方案:

一, 分析思路:

1. 现象: 通过 netstat 查看与 61616 相关的连接状况, 发现 130 多个 CLOSE_WAIT

2. 是什么原因造成这么多的 CLOSE_WAIT?

2.1 主要原因是某种情况下应用关闭了 socket 连接, 但是 mq 忙于读或者写, 没有关闭连接.

2.2 代码需要判断 socket, 一旦读到 0, 断开连接,read 返回负, 检查一下 errno,如果不是 AGAIN,就断开连接。

3. 造成 CLOSE_WAIT 之后服务为啥连不上 mq 呢?

linux 分配给一个用户的文件句柄是有限的,CLOSE_WAIT 状态一直被保持, 意味着对应数目的通道就一直被占着, 一旦达到句柄数上线, 新的请求就无法被处理了, 应用程序可能会返回大量的 Too many openfiles 异常.

4. 什么是 CLOSE_WAIT?

4.1 mq 为被连接端,java 服务为主动方, 在被动关闭情况下,mq 已经接收到 FIN, 但是还没有发送自己的 FIN 的时刻, 连接处于 CLOSE_WAIT 状态;

二, 解决办法:

1. 重启 mq

2,linux 下设置如下三个参数:

/proc/sys/net/ipv4/tcp_keepalive_time 当 keepalive 起用的时候,TCP 发送 keepalive 消息的频度。缺省是 2 小时。

/proc/sys/net/ipv4/tcp_keepalive_intvl 当探测没有确认时,重新发送探测的频度。缺省是 75 秒。

/proc/sys/net/ipv4/tcp_keepalive_probes 在认定连接失效之前,发送多少个 TCP 的 keepalive 探测包。缺省值是 9。这个值乘以 tcp_keepalive_intvl 之后决定了,一个连接发送了 keepalive 之后可以有多少时间没有回应。

三. 了解扩展

1. 客户端先发送 FIN,进入 FIN_WAIT1 状态

服务端收到 FIN,发送 ACK,进入 CLOSE_WAIT 状态,客户端收到这个 ACK,进入 FIN_WAIT2 状态
服务端发送 FIN,进入 LAST_ACK 状态
客户端收到 FIN,发送 ACK,进入 TIME_WAIT 状态,服务端收到 ACK,进入 CLOSE 状态
客户端 TIME_WAIT 持续 2 倍 MSL 时长,在 linux 体系中大概是 60s,转换成 CLOSE 状态

2. 服务端使用的短链接, 每次客户端请求后, 服务端都会主动发送 FIN 关闭连接. 最后进入到 time_wait 状态. 对于访问量大的 web server, 会存在大量的 TIME_WAIT 状态. 让服务器能够快速回收和重用那些 TIME_WAIT 的资源, 可修改内核参数.

修改 /etc/sysctl.conf 如下:
# 对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃, 不应该大于 255,默认值是 5,对应于 180 秒左右时间
net.ipv4.tcp_syn_retries=2
# 表示当 keepalive 起用的时候,TCP 发送 keepalive 消息的频度。缺省是 2 小时,改为 300 秒
net.ipv4.tcp_keepalive_time=1200

net.ipv4.tcp_orphan_retries=3
# 表示如果套接字由本端要求关闭,这个参数决定了它保持在 FIN-WAIT- 2 状态的时间
net.ipv4.tcp_fin_timeout=30
# 表示 SYN 队列的长度,默认为 1024,加大队列长度为 8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_syn_backlog = 4096
# 表示开启 SYN Cookies。当出现 SYN 等待队列溢出时,启用 cookies 来处理,可防范少量 SYN***,默认为 0,表示关闭
net.ipv4.tcp_syncookies = 1

# 表示开启重用。允许将 TIME-WAIT sockets 重新用于新的 TCP 连接,默认为 0,表示关闭
net.ipv4.tcp_tw_reuse = 1
# 表示开启 TCP 连接中 TIME-WAIT sockets 的快速回收,默认为 0,表示关闭
net.ipv4.tcp_tw_recycle = 1

## 减少超时前的探测次数
net.ipv4.tcp_keepalive_probes=5
## 优化网络设备接收队列
net.core.netdev_max_backlog=3000
修改完之后执行 /sbin/sysctl - p 让参数生效。

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-21发表,共计1897字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中