問(wèn)題:
Cannot send, channel has already failed: tcp://ip:61616
Javax.jms.JMSException: Cannot send, channel has already failed: tcp://ip:61616
應(yīng)用連不上mq
解決方案:
一,分析思路:
1.現(xiàn)象:通過(guò)netstat 查看與61616相關(guān)的連接狀況,發(fā)現(xiàn)130多個(gè)CLOSE_WAIT
2.是什么原因造成這么多的CLOSE_WAIT?
2.1 主要原因是某種情況下應(yīng)用關(guān)閉了socket連接,但是mq忙于讀或者寫(xiě),沒(méi)有關(guān)閉連接.
2.2 代碼需要判斷socket,一旦讀到0,斷開(kāi)連接,read返回負(fù),檢查一下errno,如果不是AGAIN,就斷開(kāi)連接。
3.造成CLOSE_WAIT之后服務(wù)為啥連不上mq呢?
linux分配給一個(gè)用戶(hù)的文件句柄是有限的,CLOSE_WAIT狀態(tài)一直被保持,意味著對(duì)應(yīng)數(shù)目的通道就一直被占著,一旦達(dá)到句柄數(shù)上線(xiàn),新的請(qǐng)求就無(wú)法被處理了,應(yīng)用程序可能會(huì)返回大量的Too many openfiles異常.
4.什么是CLOSE_WAIT?
4.1 mq為被連接端,java服務(wù)為主動(dòng)方,在被動(dòng)關(guān)閉情況下,mq已經(jīng)接收到FIN,但是還沒(méi)有發(fā)送自己的FIN的時(shí)刻,連接處于CLOSE_WAIT狀態(tài);
二,解決辦法:
1.重啟mq
2,linux下設(shè)置如下三個(gè)參數(shù):
/proc/sys/net/ipv4/tcp_keepalive_time當(dāng)keepalive起用的時(shí)候,TCP發(fā)送keepalive消息的頻度。缺省是2小時(shí)。
/proc/sys/net/ipv4/tcp_keepalive_intvl當(dāng)探測(cè)沒(méi)有確認(rèn)時(shí),重新發(fā)送探測(cè)的頻度。缺省是75秒。
/proc/sys/net/ipv4/tcp_keepalive_probes在認(rèn)定連接失效之前,發(fā)送多少個(gè)TCP的keepalive探測(cè)包。缺省值是9。這個(gè)值乘以tcp_keepalive_intvl之后決定了,一個(gè)連接發(fā)送了keepalive之后可以有多少時(shí)間沒(méi)有回應(yīng)。
三.了解擴(kuò)展
1.客戶(hù)端先發(fā)送FIN,進(jìn)入FIN_WAIT1狀態(tài)
服務(wù)端收到FIN,發(fā)送ACK,進(jìn)入CLOSE_WAIT狀態(tài),客戶(hù)端收到這個(gè)ACK,進(jìn)入FIN_WAIT2狀態(tài)
服務(wù)端發(fā)送FIN,進(jìn)入LAST_ACK狀態(tài)
客戶(hù)端收到FIN,發(fā)送ACK,進(jìn)入TIME_WAIT狀態(tài),服務(wù)端收到ACK,進(jìn)入CLOSE狀態(tài)
客戶(hù)端TIME_WAIT持續(xù)2倍MSL時(shí)長(zhǎng),在linux體系中大概是60s,轉(zhuǎn)換成CLOSE狀態(tài)
2.服務(wù)端使用的短鏈接,每次客戶(hù)端請(qǐng)求后,服務(wù)端都會(huì)主動(dòng)發(fā)送FIN關(guān)閉連接.最后進(jìn)入到time_wait狀態(tài).對(duì)于訪(fǎng)問(wèn)量大的web server,會(huì)存在大量的TIME_WAIT狀態(tài).讓服務(wù)器能夠快速回收和重用那些TIME_WAIT的資源,可修改內(nèi)核參數(shù).
修改/etc/sysctl.conf如下:
#對(duì)于一個(gè)新建連接,內(nèi)核要發(fā)送多少個(gè) SYN 連接請(qǐng)求才決定放棄,不應(yīng)該大于255,默認(rèn)值是5,對(duì)應(yīng)于180秒左右時(shí)間
net.ipv4.tcp_syn_retries=2
#表示當(dāng)keepalive起用的時(shí)候,TCP發(fā)送keepalive消息的頻度。缺省是2小時(shí),改為300秒
net.ipv4.tcp_keepalive_time=1200
net.ipv4.tcp_orphan_retries=3
#表示如果套接字由本端要求關(guān)閉,這個(gè)參數(shù)決定了它保持在FIN-WAIT-2狀態(tài)的時(shí)間
net.ipv4.tcp_fin_timeout=30
#表示SYN隊(duì)列的長(zhǎng)度,默認(rèn)為1024,加大隊(duì)列長(zhǎng)度為8192,可以容納更多等待連接的網(wǎng)絡(luò)連接數(shù)。
net.ipv4.tcp_max_syn_backlog = 4096
#表示開(kāi)啟SYN Cookies。當(dāng)出現(xiàn)SYN等待隊(duì)列溢出時(shí),啟用cookies來(lái)處理,可防范少量SYN***,默認(rèn)為0,表示關(guān)閉
net.ipv4.tcp_syncookies = 1
#表示開(kāi)啟重用。允許將TIME-WAIT sockets重新用于新的TCP連接,默認(rèn)為0,表示關(guān)閉
net.ipv4.tcp_tw_reuse = 1
#表示開(kāi)啟TCP連接中TIME-WAIT sockets的快速回收,默認(rèn)為0,表示關(guān)閉
net.ipv4.tcp_tw_recycle = 1
##減少超時(shí)前的探測(cè)次數(shù)
net.ipv4.tcp_keepalive_probes=5
##優(yōu)化網(wǎng)絡(luò)設(shè)備接收隊(duì)列
net.core.netdev_max_backlog=3000
修改完之后執(zhí)行/sbin/sysctl -p讓參數(shù)生效。