问题:
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让参数生效。
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。