java socket / No buffer space available
s
https://www.cnblogs.com/yiwangzhibujian/p/7107785.html
Socket用在哪呢,主要用在進程間,網絡間通信。
?
https://www.cnblogs.com/hjwublog/p/5114380.html
socket連接No buffer space available的問題,導致接口大面積調用(webservice,httpclient)失敗的問題,重啟服務器后又恢復了正常。
問題詳情
具體異常棧信息如下:
Caused by: java.net.SocketException: No buffer space available (maximum connections reached?): connectat org.apache.axis.AxisFault.makeFault(AxisFault.java:101)at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:154)at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)at org.apache.axis.client.AxisClient.invoke(AxisClient.java:165)at org.apache.axis.client.Call.invokeEngine(Call.java:2784)at org.apache.axis.client.Call.invoke(Call.java:2767)at org.apache.axis.client.Call.invoke(Call.java:2443)at org.apache.axis.client.Call.invoke(Call.java:2366)at org.apache.axis.client.Call.invoke(Call.java:1812)Caused by: java.net.SocketException: No buffer space available (maximum connections reached?): connectat java.net.PlainSocketImpl.socketConnect(Native Method)at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)at java.net.Socket.connect(Socket.java:519)at sun.reflect.GeneratedMethodAccessor24.invoke(Unknown Source)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)at java.lang.reflect.Method.invoke(Method.java:597)at org.apache.axis.components.net.DefaultSocketFactory.create(DefaultSocketFactory.java:153)at org.apache.axis.components.net.DefaultSocketFactory.create(DefaultSocketFactory.java:120)at org.apache.axis.transport.http.HTTPSender.getSocket(HTTPSender.java:191)at org.apache.axis.transport.http.HTTPSender.writeToSocket(HTTPSender.java:404)at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:138)查閱了網上的資料,基本可以把問題鎖定在:系統并發過大,連接數過多,部分socket連接無法釋放關閉,而持續請求又導致無法釋放的socket連接不斷積壓,最終導致No?buffer?space?available。
回到頂部最快解決辦法
最快的解決辦法:重啟服務器,注意,重啟tomcat不起作用。下面將分析最終的解決辦法。
回到頂部問題分析
雖然重啟服務器能最快的將socket連接釋放,但是問題很容易復現,很明顯這不是問題的根本解決方式。還有幾個問題需要進行進一步分析:
?
l?打開cmd輸入netstat?-an,發現存在大量處于TIME_WAIT狀態的TCP連接,也就是之前提到的未釋放的socket連接,并且server端口在不斷變化,這又是什么現象呢?如下如圖
?
l?系統是否有自動關閉連接的措施,是代碼問題還是性能問題?
?
下面我們來分析解決這幾個問題。
?
TIME_WAIT狀態的由來
?
我們知道,TCP關閉連接需要經過四次握手,為什么是四次握手,而不是像建立連接那樣三次握手,看看下面三次握手和四次握手的流程圖。
?
三次握手建立連接示意圖
?
四次握手關閉連接示意圖
?
從上面的三次握手建立連接示意圖中可以知道,只要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),它為服務器池提供一個共享的存儲區,這樣很容易使得服務器池擁有相同的內容,提供相同的服務。
其結構如下圖所示:
?
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連接而無法向外提供服務。
?
解決辦法,加強安全防護。
?
?
end
轉載于:https://www.cnblogs.com/lindows/p/10640700.html
總結
以上是生活随笔為你收集整理的java socket / No buffer space available的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梯度下降法实现softmax回归MATL
- 下一篇: 16个HTML5 框架、模板以及生成工具