socket-详细分析No buffer space available(转)

新年上班第一天,突然遇到一个socket连接No buffer space available的问题,导致接口大面积调用(webservice,httpclient)失败的问题,重启服务器后又恢复了正常。

问题详情

具体异常栈信息如下:

Caused by: java.net.SocketException: No buffer space available (maximum connections reached?): connect

at 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?): connect

at 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连接而无法向外提供服务。

 

解决办法,加强安全防护。

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

 

时间: 2024-07-29 22:13:29

socket-详细分析No buffer space available(转)的相关文章

Oracle AWR报告详细分析 (文档 ID 1523048.1)

Oracle AWR报告详细分析  (文档 ID 1523048.1) AWR 是 Oracle  10g 版本 推出的新特性, 全称叫Automatic Workload Repository-自动负载信息库 AWR 是通过对比两次快照(snapshot)收集到的统计信息,来生成报表数据,生成的报表包括多个部分. WORKLOAD REPOSITORY report for  DB Name DB Id Instance Inst num Release RAC Host ICCI 13140

powercat工具详细分析

本文讲的是powercat工具详细分析,这个工具出来两年了,但是好像很少人知道他.国外的大牛们用的比较多,国内的文章出现powercat关键字的寥寥无几,更别说有这款工具的详细用法了. 0x01  powercat简介 是NetCat 的Powershell 版本.作者的介绍也是这样写的,但是我觉得,powercat不管怎么样,也有比NetCat 强的一点,就是没有任何痕迹!来无影去无踪.关掉powershell 我们还是好朋友. 0x02 下载运行 直接克隆回本地: git clone htt

PHPCMS广告模块详细分析——广告的生成

本文章为原创内容,转载请注明出处. 上周班上的小范同学问我广告模块怎么设计,我说你去参考phpcms啊,他上面的广告模块设计的很不错呢. 那么,就让我们开始吧. PHPCMS广告模块详细分析--广告的生成 一.功能. 我们首先从功能开始,这里用的是最新下载的 phpcms_v9.5.2_UTF8 ,有兴趣的同学可以下载下来. 跳过安装步骤,我们进入后台,直接看广告模块. 广告位列表 广告列表 广告统计 那么,我们就很清楚phpcms广告模块的功能了. 每个广告位最多显示一个广告,但是可以设置多个

Liferay创建新用户页面中的随机文本验证详细分析

Liferay 6.1的创建新用户页面如图: 这个页面的代码在/html/portlet/login/create_account.jsp中: ... <portlet:actionURL var="createAccoutURL"> <portlet:param name="saveLastPath" value="0" /> <portlet:param name="struts_action"

详细分析使用AngularJS编程中提交表单的方式

这篇文章主要介绍了详细分析使用AngularJS提交表单的方式,AngularJS是非常热门的JavaScript库,文中展示了AngularJS在前端与后端的PHP进行交互的场景,需要的朋友可以参考下 在AngularJS出现之前,很多开发者就面对了表单提交这一问题.由于提交表单的方式繁杂而不同,很容易令人疯掉--然而现在看来,依然会让人疯掉. 今天,我们会看一下过去使用PHP方式提交的表单,现在如何将其转换为使用Angular提交.使用Angular来处理表单,对我而言,是一个"啊哈&quo

十种流行进程注入技术详细分析

本文讲的是十种流行进程注入技术详细分析, 前言 流程注入是一种恶意软件和无文件间谍攻击中使用的最为广泛的漏洞攻击技术,而且在攻击时还需要在另一个进程的地址空间内运行自定义代码.过程注入除了提高了攻击的隐蔽性之外,也实现了持久性攻击.尽管目前有许多流程注入技术,但在本文中,我只介绍十种在野外看到的能够运用另一个进程运行恶意代码的技术.在介绍的同时,我还会提供这些技术的屏幕截图,以便于逆向工程和恶意软件分析,协助针对这些常见技术进行的检测和防御. 一.经典的DLL注入 这种技术是用于将恶意软件注入另

一款勒索病毒的详细分析

原文出自看雪论坛:[原创]一款勒索病毒的详细分析-『软件逆向』-看雪安全论坛 0×01 程序信息 大小:2,132,992 字节 MD5:671ec2f2b246113f65a0afd1c53c5c3b 壳:UPX 0.89.6 - 1.02 / 1.05 - 2.90 编写语言:易语言 0×02 程序行为 开机自启 修改浏览器信息 禁用UAC 进程检测 加密文件 发送数据到指定邮箱 0×03 运行截图 0×04 脱壳去花指令 采用UPX加壳,通过ESP定律脱壳 脱壳后: 从入口特征判断为VC+

编程c语言-这个程序详细分析~~~求大神

问题描述 这个程序详细分析~~~求大神 看了半天弄不清 解决方案 这是一个函数递归调用的例题,首先n=5,调用age函数,此时n!=1,所以直接执行else语句,t=age(4)+2,(age(4)的值等于age(3)+2)n=4>1,第二次调用age函数,再次执行else语句,返回的是t=age(3)+2,(age(2)+2)以此类推,当第五次调用age函数时,n==1,所以第五次返回的是10,所以最终的结果是10+2+2+2+2=18. 解决方案二: 总共有4层递归,最深的一层递归时n=1,

Linux内核OOM机制的详细分析(转)

Linux 内核 有个机制叫OOM killer(Out-Of-Memory killer),该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了 防止内存耗尽而内核会把该进程杀掉.典型的情况是:某天一台机器突然ssh远程登录不了,但能ping通,说明不是网络的故障,原因是sshd进程被 OOM killer杀掉了(多次遇到这样的假死状况).重启机器后查看系统日志/var/log/messages会发现 Out of Memory: Kill process 1865(sshd)