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
socket-详细分析No buffer space available(转)的更多相关文章
- socket-详细分析No buffer space available
关键词:socket,tcp三次握手,tcp四次握手,2MSL最大报文生存时间,LVS,负载均衡 新年上班第一天,突然遇到一个socket连接No buffer space available的问题, ...
- socket-详细分析No buffer space available(转载)
文章原文出处:http://www.cnblogs.com/hjwublog/p/5114380.html 今天在公司服务器上部署运行的后台程序出现大面积接口无法调用的问题,查看后台控制台打印如下信息 ...
- Struct Socket详细分析(转)
原文地址:http://anders0913.iteye.com/blog/411986 用户使用socket系统调用编写应用程序时,通过一个数字来表示一个socket,所有的操作都在该数字上进行,这 ...
- java socket / No buffer space available
s https://www.cnblogs.com/yiwangzhibujian/p/7107785.html Socket用在哪呢,主要用在进程间,网络间通信. https://www.cnblo ...
- An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误.未找到或无法访问服务器.请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接. (provider: TCP ...
- 详细分析MySQL事务日志(redo log和undo log)
innodb事务日志包括redo log和undo log.redo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作. undo log不是redo log的逆向过程,其实它 ...
- 详细分析MySQL事务日志(redo log和undo log) 表明了为何mysql不会丢数据
innodb事务日志包括redo log和undo log.redo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作. undo log不是redo log的逆向过程,其实它 ...
- 1125MySQL Sending data导致查询很慢的问题详细分析
-- 问题1 tablename使用主键索引反而比idx_ref_id慢的原因EXPLAIN SELECT SQL_NO_CACHE COUNT(id) FROM dbname.tbname FORC ...
- java.net.SocketException: No buffer space available
https 访问url在调用量不大的情况下 java.net.SocketException: No buffer space available (maximum connections reach ...
随机推荐
- python之字符串的分割和拼接
关于string的split 和 join 方法 对导入os模块进行os.path.splie()/os.path.join() 貌似是处理机制不一样,但是功能上一样. 1.string.split( ...
- J2SE基础:1.类和对象基础
什么是对象 在Java语言,全部的人,事物或者模块都是一个对象. 同样的对象具有一些同样的特性. 狗,猫,蛇3个对象(动物的对象) 苹果,梨,桔子3个对象(水果的对象) 什么是类 能够将现实生活中的对 ...
- PHP --字符串编码转换(自动识别原编码)
/** * 对数据进行编码转换 * @param array/string $data 数组 * @param string $output 转换后的编码 */ function array_icon ...
- wamp无法登录phpmyadmin问题
文章来源:PHP座谈会 地址:http://bbs.phpthinking.com/forum.php? mod=viewthread&tid=163 第一步.用navicat确认一下,自己的 ...
- 【剑指offer】第一个字符只出现一次
转载请注明出处:http://blog.csdn.net/ns_code/article/details/27106997 题目描写叙述: 在一个字符串(1<=字符串长度<=10000,所 ...
- C#中禁止程序多开
原文:C#中禁止程序多开 方法一.使用Mutex bool createdNew; //返回是否赋予了使用线程的互斥体初始所属权 System.Threading.Mutex i ...
- CodeForces 22D Segments 排序水问题
主题链接:点击打开链接 升序右键点.采取正确的点 删边暴力 #include <cstdio> #include <cstring> #include <algorith ...
- C++ - 内置类型的最大值宏定义
内置类型的最大值宏定义 本文地址: http://blog.csdn.net/caroline_wendy/article/details/24311895 C++中, 常常会使用, 某些类型的最大值 ...
- Android源代码学习之六——ActivityManager框架解析
ActivityManager在操作系统中有关键的数据,本文利用操作系统源代码,逐步理清ActivityManager的框架,并从静态类结构图和动态序列图两个角度分别进行剖析,从而帮助开发者加强对系统 ...
- MapReduce源代码分析MapTask分析
前言 MapReduce该分析是基于源代码Hadoop1.2.1代码分析进行的基础上. 该章节会分析在MapTask端的详细处理流程以及MapOutputCollector是怎样处理map之后的col ...