最近網關服務器系統頻發soket客戶端連接自動斷開且 無法再進行通信,開始沒有太過深入調查 重啓網關既恢復了,但另一天又重複出現,懷疑是不是有線程死鎖導致socketserver 服務阻塞,所以仔細分析了下問題, 過程如下:
1. 首先netstat -apn PID |grep port 發現情況:
大量的連接都處於CLOSED_WAIT狀態 懷疑服務端沒有正常關閉客戶端連接。
2.然後jstack pid (jstack 生成當時jvm線程的狀態及運行情況) 發現並沒有異常信息 ,沒有線程處於異常狀態。
3.用top -Hp pid 查詢進程下所有線程的運行情況(shift+p 按cpu排序,shift+m 按內存排序)
沒有CUP使用很高的線程。
綜上的調查及連接端口close_wait查閱資料發現 linux 打開文件的句柄/socket是有限制的,通過ulimit -a 發現
最大打開文件句柄數是1024,分析是socket最大連接數超過1024 ,但系統連接的客戶端最大600,怎麼可能超過1024呢,而且連接出現close_wait 狀態,證明連接並未被關閉。
在socket全雙工通信過程中有如下幾種狀態:
LISTEN - 偵聽來自遠方TCP端口的連接請求;
SYN-SENT -在發送連接請求後等待匹配的連接請求;
SYN-RECEIVED - 在收到和發送一個連接請求後等待對連接請求的確認;
ESTABLISHED- 代表一個打開的連接,數據可以傳送給用戶;
FIN-WAIT-1 - 等待遠程TCP的連接中斷請求,或先前的連接中斷請求的確認;
FIN-WAIT-2 - 從遠程TCP等待連接中斷請求;
CLOSE-WAIT - 等待從本地用戶發來的連接中斷請求;
CLOSING -等待遠程TCP對連接中斷的確認;
LAST-ACK - 等待原來發向遠程TCP的連接中斷請求的確認;
TIME-WAIT -等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認;
CLOSED - 沒有任何連接狀態;
原因分析:在TCP/IP協議中,TCP提供可靠的連接服務,連接採用三次握手建立,由於連接是全雙工的,關閉連接時,每個方向都要單獨關閉,連接拆除需要發送來回共發送四個包,因此叫做四次揮手,任何一個過程中途沒接受到消息都會停留在某一個狀態,很明顯目前大部分連接停留在close_wait 狀態,等待超時讀取時間關閉,一旦超時過長或未設置 併發量過大就容易導致客戶端連接數過大,超過linux 設置的open_files ,就導致端口被佔滿,發生 many open files無法通信。
解決辦法:
a) 修改linux open files 參數爲65535
查詢linux open file參數命令 :ulimit -a
修改參數方法:
1)ulimit -n 65536 修改當前會話的 open files 參數 只能臨時改動參數 重新登錄參數失效
2)使用ROOT 用戶登 修改文件/etc/security/limits.conf 添加:
xxx - nofile 65535
xxx 是一個用戶,如果是想所有用戶生效的話換成 * ,設置的數值與硬件配置有關,別設置太大了。
b) 設置socket讀取超時關閉時間或者更短 socket.setTimeout(3000);