1 通常緣由都是TCP鏈接沒有調用關閉方法。須要應用來處理網絡連接關閉。 2 對於Web請求出現這個緣由,常常是由於Response的BodyStream沒有調用Close. 好比Widnows下: 使用HttpWebRequest 必定要保證GetRequestStream和GetResponse對象關閉,不然容易形成鏈接處於CLOSE_WAIT狀態 3 TCP的KeepLive功能,可讓操做系統替咱們自動清理掉CLOSE_WAIT的鏈接。 可是KeepLive在Windows操做系統下默認是7200秒,也就是2個小時才清理一次。每每知足不了要求。能夠調小該數值。 Windows下的調整方法爲 HKEY_LOCAL_MACHINE/CurrentControlSet/Services/Tcpip/Parameters下的如下三個參數: KeepAliveInterval,設置其值爲1000 www.2cto.com
KeepAliveTime,設置其值爲300000(單位爲毫秒,300000表明5分鐘) TcpMaxDataRetransmissions,設置其值爲5 Close_Wait引起的問題: Close_Wait會佔用一個鏈接,網絡可用鏈接小。數量過多,可能會引發網絡性能降低,並佔用系統非換頁內存。 尤爲是在有鏈接池的狀況下(好比HttpRequest) 會耗盡鏈接池的網絡鏈接數,致使沒法創建網絡鏈接服務器
----引自紅黑聯盟的《TCP的狀態兼談Close_Wait和Time_Wait的狀態》網絡
生產環境和測試環境都發現有個外圍應用經過搜索服務調用搜索引擎時,偶爾會出現大量的訪問超時的問題,經過以下方式進行分析排查: l 首先是拿到搜索服務的JavaCore,發現其堵在HttpClient的發送上面,被堵的鏈接有數百個,緣由是不可以從鏈接池中獲取到鏈接; l 首先想到的就是鏈接池沒有釋放,檢查代碼,也確實存在着一些調用沒有釋放鏈接,特別是在異常的狀況下,針對這一部分代碼進行修復後,但是一段時間以後仍是出現了訪問超時的問題; l 考慮到這個外圍應用的訪問現出問題的時候,其它的外圍應用調用搜索服務是沒有問題的,所以肯定當前搜索服務尚未掛; l 不一樣的外圍應用可能調用的後臺搜索引擎是不同的,難道是該外圍應用對應的搜索引擎出現了問題?不過通過對該搜索引擎進行分析,該搜索引擎自己是正常的,可是有一個奇怪的現象,在外圍應用調用搜索服務發生超時時,搜索引擎自己沒有接受到任何請求; l 也就是說經搜索服務的請求都沒有提交到該搜索引擎上,難道是搜索服務與該搜索引擎之間的鏈接有問題?經過網絡排查,使用Ping和Telnet進行正向和反向肯定,從搜索服務和搜索引擎之間的網絡是正常的,且端口也能夠正常訪問; l 再回到搜索服務所在的服務器,經過netstat一看,發現有400個CLOSE_WAIT與該搜索引擎相關的鏈接,這個數字剛好是應用中設置的單個Route所可以鏈接的最大鏈接數。tcp
分析到此,問題就明朗了,HttpClient鏈接池的中建立鏈接數已經達到了最大數字,不可以建立新的鏈接了,已經建立的鏈接都是在等待關閉(CLOSE_WAIT)的狀態,沒有被放回到可用的鏈接池中,不可以用於處理新的鏈接請求,於是全部的請求都是堵在了從鏈接池中獲取鏈接哪裏。 要解決這個問題,首先須要知道CLOSE_WAIT產生的緣由,纔可以解決該問題,或者減小該問題的發生。 TCP鏈接關閉時須要四次握手纔可以完成,以下圖所示:工具
產生CLOSE_WAIT狀態的一方,是屬於被動關閉的一方,用簡單的話對解釋上圖(主動關閉方爲A,被動關閉方爲B): A發一條FIN(關閉)請求給B,說我要關閉了; B迴應一條ACK(確認)請求給A,說我知道了,你關吧,此時B就會進行CLOSE_WAIT狀態; B發送一條FIN(關閉)請給A,說我要關閉了; A收到發送一條ACK(確認)消息說,你關閉吧。性能
上面四次握手完成後,雙方的鏈接就都關閉了,可是這裏在客戶端產生了CLOSE_WAIT現象,首先能夠肯定的是服務端主動關閉的鏈接,且客戶端沒有給服務端發送關閉的請求(第三次握手請求),就會一直處在CLOSE_WAIT的狀態,但是客戶端爲何不向服務端發送關閉的請求,它當時在忙什麼呢,難道應用在關閉前有哪麼多事情要作?還有就是爲何服務會主動關掉客戶端的這麼多鏈接? 有人說這多是服務端在調用關閉時,而客戶端正在執行RECV(數據接收),這時候有可能服務端發送的FIN包客戶端接收出錯,就是由TCP代回了一個ACK包,因此客戶端就會處在CLOSE_WAIT的狀態中,於是建議判斷RECV時是否出錯,若是出錯就主動關閉鏈接,這樣就能夠防止沒有接收到FIN包。 也有人說這是因爲客戶端請求服務端時,超時就有可能出現這種狀況,我對這種狀況作了實驗,分別啓動了客戶端和服務端,在服務端中暴露一個超時的服務接口,在客戶端中經過POST的方式調用,而後再經過第三方工具調用客戶端去調用服務端的超時接口,測試分別在Linux以及Windows平臺進行了測試,但是通過100萬個鏈接超時的請求後,客戶端沒有出現CLOSE-WAIT的現象,只有服務端纔出現了CLOSE-WAIT,而且都會正常的關閉。 咱們嘗試過優化Linux中TCP鏈接參數,減小TCP的鏈接時間以及增長鏈接的可用性,以下: sysctl -w net.ipv4.tcp_timestamps=0 sysctl -w net.ipv4.tcp_tw_reuse=1 sysctl -w net.ipv4.tcp_tw_recycle=1 sysctl -w net.ipv4.tcp_fin_timeout=30 sysctl -w net.ipv4.tcp_keepalive_time=1800 sysctl -w net.ipv4.tcp_rmem="4096 87380 8388608" sysctl -w net.ipv4.tcp_wmem="4096 87380 8388608" sysctl -w net.ipv4.tcp_max_syn_backlog=4096 也優化了HttpClient的參數,但是客戶端仍是會出現CLOSE_WAIT的狀況,且搜索引擎是使用惠普的Autonomy,閉源的很差入手優化,最後仍是經過在客戶端實現定時任務按期檢查當前鏈接中狀態爲leased(拿走但沒有返回aviable可用隊列中的鏈接)的鏈接的數量,檢測到該這種鏈接的數量超過必定數量後,就關閉該鏈接池,釋放全部鏈接,而後從新初使化該鏈接池,就能夠解決這種問題了,通過測試這種試是可行的。不過曾經考慮到這種方式比較暴力,連可用的鏈接都給關閉了,本想只關閉那些長久未釋放的鏈接,不過因爲鏈接池沒有暴露操做方法,經過反射能夠獲取到池中的鏈接,不過因爲關聯資源較多,操做麻煩,最後沒有采用這種方式。測試