No buffer space available 一次神奇的维护经历

版权声明:原创文章欢迎转载,转载请备注来源:https://blog.csdn.net/weixin_41986096 欢迎关注微信公众号摘星族 https://blog.csdn.net/weixin_41986096/article/details/82258305

前段时间在项目维护当中遇见一个问题,方便以后再次遇见类似的问题,可以参考解决问题的思路,记录如下:

问题概述:

维护项目当中,客户这边发来消息,称自己的网站登录不上去了,提示用户名密码错误,我就登录到服务器上查看系统日志和报错情况,如图:

这个异常来源部署的一个jar包,用于读取数据存入mongodb,再看了Tomcat也报错了,错误是:java.net.SocketException。看完这样的问题后,没有确切的解决方案,自己一脸懵逼无奈的重新启动服务,可以正常登陆。没有什么问题是重启解决不了的。

问题分析:

虽然重启服务能暂时以最快的速度解决问题,但是问题很容易复现,很明显,这个并不是根本的解决方案。

需要进行进一步的分析:


总结下来根据我们当时的代码和部署的系统有可能出现的原因:

  • 1:因为首先看到的是mongodb的问题,所以猜测是mongodb链接数不够,而需要等待的链接数过多,导致资源无法尽快释放。

  • 2:因为代码内部使用有很多的 HttpClient请求,调用另一个数据库的数据,可能是请求量过多,或者是请求未正常的关闭。导致内部资源泄露

  • 3:系统并发量太大,链接数过多,部分系统或者非系统请求无法正常的释放关闭,而又持续请求,导致socket链接不断进行积压,从而导致系统崩溃。


根据以上分析,我们对系统进行了内部的测试。让错误重现。




通过cmd输入netstat -an 发现有大量处于TIME_WAIT状态的TCP链接,也就是那些Socket未释放的链接

那么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
问题的发生

最终解决办法:

1:关闭不需要的链接:

  • 检查在代码当中是否有请求完的链接没有正常关闭,如:HttpClient请求中链接是否正常关闭, 
    Mongodb读取数据时链接是否正常关闭,及时关闭请求链接和clean,使用

     try{}catch(){}finally{}

    释放请求,及时回收资源,避免内存溢出。

2:通过修改注册表进行配置,减少等待时间


通过regedit启动注册表编译器找到如下路径:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

添加参数:

(1)新建

  • 值名称:MaxUserPort

  • 值类型:DWORD

  • 值数据:65534(十六进制是FFFE)

  • 有效范围:5000 - 65534 (十进制)

  • 默认:0x1388 5000(十进制)

(2)新建

  • 值名称:TCPTimedWaitDelay

  • 值类型:DWORD

  • 值数据:0000001e(30) 

欢迎关注

猜你喜欢

转载自blog.csdn.net/weixin_41986096/article/details/82258305