天天看點

socket-詳細分析No buffer space available(轉)

新年上班第一天,突然遇到一個socket連接配接No buffer space available的問題,導緻接口大面積調用(webservice,httpclient)失敗的問題,重新開機伺服器後又恢複了正常。

具體異常棧資訊如下:

socket-詳細分析No buffer space available(轉)
socket-詳細分析No buffer space available(轉)

查閱了網上的資料,基本可以把問題鎖定在:系統并發過大,連接配接數過多,部分socket連接配接無法釋放關閉,而持續請求又導緻無法釋放的socket連接配接不斷積壓,最終導緻No buffer space available。

最快的解決辦法:重新開機伺服器,注意,重新開機tomcat不起作用。下面将分析最終的解決辦法。

雖然重新開機伺服器能最快的将socket連接配接釋放,但是問題很容易複現,很明顯這不是問題的根本解決方式。還有幾個問題需要進行進一步分析:

l 打開cmd輸入netstat -an,發現存在大量處于TIME_WAIT狀态的TCP連接配接,也就是之前提到的未釋放的socket連接配接,并且server端口在不斷變化,這又是什麼現象呢?如下如圖

socket-詳細分析No buffer space available(轉)

l 系統是否有自動關閉連接配接的措施,是代碼問題還是性能問題?

下面我們來分析解決這幾個問題。

TIME_WAIT狀态的由來

我們知道,TCP關閉連接配接需要經過四次握手,為什麼是四次握手,而不是像建立連接配接那樣三次握手,看看下面三次握手和四次握手的流程圖。

socket-詳細分析No buffer space available(轉)

              三次握手建立連接配接示意圖

socket-詳細分析No buffer space available(轉)

              四次握手關閉連接配接示意圖

從上面的三次握手建立連接配接示意圖中可以知道,隻要client端和server端都接收到了對方發送的ACK應答之後,雙方就可以建立連接配接,之後就可以進行資料互動了,這個過程需要三步。

而四次握手關閉連接配接示意圖中,TCP協定中,關閉TCP連接配接的是Server端(當然,關閉都可以由任意一方發起),當Server端發起關閉連接配接請求時,向Client端發送一個FIN封包,Client端收到FIN封包時,很可能還有資料需要發送,是以并不會立即關閉SOCKET,是以先回複一個ACK封包,告訴Server端,“你發的FIN封包我收到了”。當Client端的所有封包都發送完畢之後,Client端向Server端發送一個FIN封包,此時Client端進入關閉狀态,不在發送資料。

Server端收到FIN封包後,就知道可以關閉連接配接了,但是網絡是不可靠的,Client端并不知道Server端要關閉,是以Server端發送ACK後進入TIME_WAIT狀态,如果Client端沒有收到ACK則Server段可以重新發送。Client端收到ACK後,就知道可以斷開連接配接了。Server端等待了2MSL(Max Segment Lifetime,最大封包生存時間)後依然沒有收到回複,則證明Client端已正常斷開,此時,Server端也可以斷開連接配接了。2MSL的TIME_WAIT等待時間就是由此而來。

我們知道了TIME_WAIT的由來,TIME_WAIT 狀态最大保持時間是2 * MSL,在1-4分鐘之間,是以當系統并發過大,Client-Server連接配接數過多,Server端會在1-4分鐘之内積累大量處于TIME_WAIT狀态的無法釋放的socket連接配接,導緻伺服器效率急劇下降,甚至耗完伺服器的所有資源,最終導緻No buffer space available (maximum connections reached?): connect

問題的發生。

端口變化由來

對于大型的應用,通路量較高,一台Server往往不能滿足服務需求,這時就需要多台Server共同對外提供服務。如何充分、最大的利用多台Server的資源處理請求,這時就需要請求排程,将請求合理均勻的配置設定到各台Server。

LVS (Linux Virtual Server)叢集(Cluster)技術就是實作這一需求的方式之一。采用IP負載均衡技術和基于内容請求分發技術。排程器具有很好的吞吐率,将請求均衡地轉移到不同的伺服器上執行,且排程器自動屏蔽掉伺服器的故障,進而将一組伺服器構成一個高性能的、高可用的虛拟伺服器。

LVS叢集采用三層結構,其主要組成部分為:

l 負載均衡排程器(load balancer),它是整個叢集對外面的前端機,負責将客戶的請求發送到一組伺服器上執行,而客戶認為服務是來自一個IP位址(我們可稱之為虛拟IP位址)上的。

l 伺服器池(server pool),是一組真正執行客戶請求的伺服器,執行的服務有WEB、MAIL、FTP和DNS等。

l 共享存儲(shared storage),它為伺服器池提供一個共享的存儲區,這樣很容易使得伺服器池擁有相同的内容,提供相同的服務。

其結構如下圖所示:

socket-詳細分析No buffer space available(轉)

              LVS結構示意圖

從LVS結構示意圖中可以看出,Load Balancer到後端Server的IP的資料包的 源IP位址都是一樣(Load Balancer的IP位址和Server 的IP位址屬于同一網段),而用戶端認為服務是來自一個IP位址(實際上就是Load Balancer的IP),頻繁的TCP連接配接建立和關閉,使得Load Balancer到後端Server的TCP連接配接會受到限制,導緻在server上留下很多處于TIME_WAIT狀态的連接配接,而且這些狀态對應的遠端IP位址都是Load Balancer的。Load Balancer的端口最多也就60000多個(2^16=65536,1~1023是保留端口,還有一些其他端口預設也不會用),每個Load Balancer上的端口一旦進入 Server的TIME_WAIT黑名單,就有240秒不能再用來建立和Server的連接配接,這樣Load Balancer和Server的連接配接就很有限。是以我們看到了使用netstat -an指令檢視網絡連接配接狀況時同一個 remote IP會有很多端口。

從上面的分析來看,導緻出現No buffer space available這一問題的原因是多方面的,原因以及解決辦法如下:

l 從代碼層面上看,webservice或httpclient調用未進行連接配接釋放,導緻資源無法回收。

解決辦法是在axis2的用戶端代碼中進行連接配接關閉,如下:

stub._getServiceClient().cleanupTransport();   stub._getServiceClient().cleanup();     stub.cleanup();     stub = null;

及時的關閉和clean能有效的避免記憶體溢出的問題,及時回收資源。

或者httpClient中,最終要在finally調用response.close()或者httpPost.releaseConnection() 進行連接配接釋放。

l 從系統層面上看,系統socket連接配接數設定不合理,socket連接配接數過小,易達到上限;其次是2MSL設定過長,容易積壓TIME_WAIT狀态的TCP連接配接。

解決辦法是修改Linux核心參數,

修改系統socket最大連接配接數,在檔案/etc/security/limits.conf最後加入下面兩行:

* soft nofile 32768

* hard nofile 32768

或者縮小2MSL的時長、允許重用處于TIME_WAIT狀态的TCP連接配接、快速回收處于 TIME_WAIT狀态的TCP連接配接,修改/etc/sysctl.conf,添加如下幾行:

#改系統預設的TIMEOUT時間 net.ipv4.tcp_fin_timeout=2

#啟重用,允許将TIME_WAIT sockets重新用于新的TCP連接配接 預設為0表示關閉 net.ipv4.tcp_tw_reuse=1

#開啟TCP連接配接中TIME_WAIT sockets的快速回收 預設為0 表示關閉 net.ipv4.tcp_tw_recycle=1

對于windows環境,可通過修改系統資料庫進行配置:

\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

添加一個DWORD類型的值TcpTimedWaitDelay,值可以根據實際情況配置。

\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters

添加一個DWORD類型的值MaxUserPort ,值可以根據實際情況配置。

上面這些參數根據實際情況進行配置。

l 從LVS 層面上看,排程算法不合理,導緻請求過多配置設定到某一台伺服器上。

解決辦法,根據實際情況指定合理的負載均衡解決方案。

l 從安全層面上看,當伺服器遭到DDoS(拒絕服務攻擊)時,伺服器大量積壓TIME_WAIT狀态的TCP連接配接而無法向外提供服務。

解決辦法,加強安全防護。

http://www.cnblogs.com/hjwublog/p/5114380.html

繼續閱讀