java socket / No buffer space available
s
https://www.cnblogs.com/yiwangzhibujian/p/7107785.html
Socket用在哪呢,主要用在進(jìn)程間,網(wǎng)絡(luò)間通信。
?
https://www.cnblogs.com/hjwublog/p/5114380.html
socket連接No buffer space available的問(wèn)題,導(dǎo)致接口大面積調(diào)用(webservice,httpclient)失敗的問(wèn)題,重啟服務(wù)器后又恢復(fù)了正常。
問(wèn)題詳情
具體異常棧信息如下:
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)查閱了網(wǎng)上的資料,基本可以把問(wèn)題鎖定在:系統(tǒng)并發(fā)過(guò)大,連接數(shù)過(guò)多,部分socket連接無(wú)法釋放關(guān)閉,而持續(xù)請(qǐng)求又導(dǎo)致無(wú)法釋放的socket連接不斷積壓,最終導(dǎo)致No?buffer?space?available。
回到頂部最快解決辦法
最快的解決辦法:重啟服務(wù)器,注意,重啟tomcat不起作用。下面將分析最終的解決辦法。
回到頂部問(wèn)題分析
雖然重啟服務(wù)器能最快的將socket連接釋放,但是問(wèn)題很容易復(fù)現(xiàn),很明顯這不是問(wèn)題的根本解決方式。還有幾個(gè)問(wèn)題需要進(jìn)行進(jìn)一步分析:
?
l?打開(kāi)cmd輸入netstat?-an,發(fā)現(xiàn)存在大量處于TIME_WAIT狀態(tài)的TCP連接,也就是之前提到的未釋放的socket連接,并且server端口在不斷變化,這又是什么現(xiàn)象呢?如下如圖
?
l?系統(tǒng)是否有自動(dòng)關(guān)閉連接的措施,是代碼問(wèn)題還是性能問(wèn)題?
?
下面我們來(lái)分析解決這幾個(gè)問(wèn)題。
?
TIME_WAIT狀態(tài)的由來(lái)
?
我們知道,TCP關(guān)閉連接需要經(jīng)過(guò)四次握手,為什么是四次握手,而不是像建立連接那樣三次握手,看看下面三次握手和四次握手的流程圖。
?
三次握手建立連接示意圖
?
四次握手關(guān)閉連接示意圖
?
從上面的三次握手建立連接示意圖中可以知道,只要client端和server端都接收到了對(duì)方發(fā)送的ACK應(yīng)答之后,雙方就可以建立連接,之后就可以進(jìn)行數(shù)據(jù)交互了,這個(gè)過(guò)程需要三步。
?
而四次握手關(guān)閉連接示意圖中,TCP協(xié)議中,關(guān)閉TCP連接的是Server端(當(dāng)然,關(guān)閉都可以由任意一方發(fā)起),當(dāng)Server端發(fā)起關(guān)閉連接請(qǐng)求時(shí),向Client端發(fā)送一個(gè)FIN報(bào)文,Client端收到FIN報(bào)文時(shí),很可能還有數(shù)據(jù)需要發(fā)送,所以并不會(huì)立即關(guān)閉SOCKET,所以先回復(fù)一個(gè)ACK報(bào)文,告訴Server端,“你發(fā)的FIN報(bào)文我收到了”。當(dāng)Client端的所有報(bào)文都發(fā)送完畢之后,Client端向Server端發(fā)送一個(gè)FIN報(bào)文,此時(shí)Client端進(jìn)入關(guān)閉狀態(tài),不在發(fā)送數(shù)據(jù)。
?
Server端收到FIN報(bào)文后,就知道可以關(guān)閉連接了,但是網(wǎng)絡(luò)是不可靠的,Client端并不知道Server端要關(guān)閉,所以Server端發(fā)送ACK后進(jìn)入TIME_WAIT狀態(tài),如果Client端沒(méi)有收到ACK則Server段可以重新發(fā)送。Client端收到ACK后,就知道可以斷開(kāi)連接了。Server端等待了2MSL(Max?Segment?Lifetime,最大報(bào)文生存時(shí)間)后依然沒(méi)有收到回復(fù),則證明Client端已正常斷開(kāi),此時(shí),Server端也可以斷開(kāi)連接了。2MSL的TIME_WAIT等待時(shí)間就是由此而來(lái)。
?
我們知道了TIME_WAIT的由來(lái),TIME_WAIT?狀態(tài)最大保持時(shí)間是2?*?MSL,在1-4分鐘之間,所以當(dāng)系統(tǒng)并發(fā)過(guò)大,Client-Server連接數(shù)過(guò)多,Server端會(huì)在1-4分鐘之內(nèi)積累大量處于TIME_WAIT狀態(tài)的無(wú)法釋放的socket連接,導(dǎo)致服務(wù)器效率急劇下降,甚至耗完服務(wù)器的所有資源,最終導(dǎo)致No?buffer?space?available?(maximum?connections?reached?):?connect
問(wèn)題的發(fā)生。
?
端口變化由來(lái)
?
對(duì)于大型的應(yīng)用,訪問(wèn)量較高,一臺(tái)Server往往不能滿足服務(wù)需求,這時(shí)就需要多臺(tái)Server共同對(duì)外提供服務(wù)。如何充分、最大的利用多臺(tái)Server的資源處理請(qǐng)求,這時(shí)就需要請(qǐng)求調(diào)度,將請(qǐng)求合理均勻的分配到各臺(tái)Server。
?
LVS?(Linux?Virtual?Server)集群(Cluster)技術(shù)就是實(shí)現(xiàn)這一需求的方式之一。采用IP負(fù)載均衡技術(shù)和基于內(nèi)容請(qǐng)求分發(fā)技術(shù)。調(diào)度器具有很好的吞吐率,將請(qǐng)求均衡地轉(zhuǎn)移到不同的服務(wù)器上執(zhí)行,且調(diào)度器自動(dòng)屏蔽掉服務(wù)器的故障,從而將一組服務(wù)器構(gòu)成一個(gè)高性能的、高可用的虛擬服務(wù)器。
LVS集群采用三層結(jié)構(gòu),其主要組成部分為:
l?負(fù)載均衡調(diào)度器(load?balancer),它是整個(gè)集群對(duì)外面的前端機(jī),負(fù)責(zé)將客戶的請(qǐng)求發(fā)送到一組服務(wù)器上執(zhí)行,而客戶認(rèn)為服務(wù)是來(lái)自一個(gè)IP地址(我們可稱之為虛擬IP地址)上的。
l?服務(wù)器池(server?pool),是一組真正執(zhí)行客戶請(qǐng)求的服務(wù)器,執(zhí)行的服務(wù)有WEB、MAIL、FTP和DNS等。
l?共享存儲(chǔ)(shared?storage),它為服務(wù)器池提供一個(gè)共享的存儲(chǔ)區(qū),這樣很容易使得服務(wù)器池?fù)碛邢嗤膬?nèi)容,提供相同的服務(wù)。
其結(jié)構(gòu)如下圖所示:
?
LVS結(jié)構(gòu)示意圖
?
從LVS結(jié)構(gòu)示意圖中可以看出,Load?Balancer到后端Server的IP的數(shù)據(jù)包的 源IP地址都是一樣(Load?Balancer的IP地址和Server?的IP地址屬于同一網(wǎng)段),而客戶端認(rèn)為服務(wù)是來(lái)自一個(gè)IP地址(實(shí)際上就是Load?Balancer的IP),頻繁的TCP連接建立和關(guān)閉,使得Load?Balancer到后端Server的TCP連接會(huì)受到限制,導(dǎo)致在server上留下很多處于TIME_WAIT狀態(tài)的連接,而且這些狀態(tài)對(duì)應(yīng)的遠(yuǎn)程IP地址都是Load?Balancer的。Load?Balancer的端口最多也就60000多個(gè)(2^16=65536,1~1023是保留端口,還有一些其他端口缺省也不會(huì)用),每個(gè)Load?Balancer上的端口一旦進(jìn)入?Server的TIME_WAIT黑名單,就有240秒不能再用來(lái)建立和Server的連接,這樣Load?Balancer和Server的連接就很有限。所以我們看到了使用netstat?-an命令查看網(wǎng)絡(luò)連接狀況時(shí)同一個(gè)?remote?IP會(huì)有很多端口。
回到頂部最終解決辦法
從上面的分析來(lái)看,導(dǎo)致出現(xiàn)No?buffer?space?available這一問(wèn)題的原因是多方面的,原因以及解決辦法如下:
?
l?從代碼層面上看,webservice或httpclient調(diào)用未進(jìn)行連接釋放,導(dǎo)致資源無(wú)法回收。
?
解決辦法是在axis2的客戶端代碼中進(jìn)行連接關(guān)閉,如下:
stub._getServiceClient().cleanupTransport();
?? stub._getServiceClient().cleanup();
????stub.cleanup();
????stub?=?null;
及時(shí)的關(guān)閉和clean能有效的避免內(nèi)存溢出的問(wèn)題,及時(shí)回收資源。
或者h(yuǎn)ttpClient中,最終要在finally調(diào)用response.close()或者h(yuǎn)ttpPost.releaseConnection() 進(jìn)行連接釋放。
?
l?從系統(tǒng)層面上看,系統(tǒng)socket連接數(shù)設(shè)置不合理,socket連接數(shù)過(guò)小,易達(dá)到上限;其次是2MSL設(shè)置過(guò)長(zhǎng),容易積壓TIME_WAIT狀態(tài)的TCP連接。
?
解決辦法是修改Linux內(nèi)核參數(shù),
修改系統(tǒng)socket最大連接數(shù),在文件/etc/security/limits.conf最后加入下面兩行:
*?soft?nofile?32768
*?hard?nofile?32768
或者縮小2MSL的時(shí)長(zhǎng)、允許重用處于TIME_WAIT狀態(tài)的TCP連接、快速回收處于 TIME_WAIT狀態(tài)的TCP連接,修改/etc/sysctl.conf,添加如下幾行:
?
#改系統(tǒng)默認(rèn)的TIMEOUT時(shí)間
net.ipv4.tcp_fin_timeout=2
#啟重用,允許將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
?
對(duì)于windows環(huán)境,可通過(guò)修改注冊(cè)表進(jìn)行配置:
\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
添加一個(gè)DWORD類(lèi)型的值TcpTimedWaitDelay,值可以根據(jù)實(shí)際情況配置。
\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters
添加一個(gè)DWORD類(lèi)型的值MaxUserPort?,值可以根據(jù)實(shí)際情況配置。
?
上面這些參數(shù)根據(jù)實(shí)際情況進(jìn)行配置。
?
l?從LVS?層面上看,調(diào)度算法不合理,導(dǎo)致請(qǐng)求過(guò)多分配到某一臺(tái)服務(wù)器上。
?
解決辦法,根據(jù)實(shí)際情況指定合理的負(fù)載均衡解決方案。
?
l?從安全層面上看,當(dāng)服務(wù)器遭到DDoS(拒絕服務(wù)攻擊)時(shí),服務(wù)器大量積壓TIME_WAIT狀態(tài)的TCP連接而無(wú)法向外提供服務(wù)。
?
解決辦法,加強(qiáng)安全防護(hù)。
?
?
end
轉(zhuǎn)載于:https://www.cnblogs.com/lindows/p/10640700.html
總結(jié)
以上是生活随笔為你收集整理的java socket / No buffer space available的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 梯度下降法实现softmax回归MATL
- 下一篇: 志宇-OCR