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


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

    问题概述:

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

    这个异常来源部署的一个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_MACHINESYSTEMCurrentControlSetServicesTcpipParameters
    

    添加参数:

    (1)新建

    • 值名称:MaxUserPort

    • 值类型:DWORD

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

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

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

    (2)新建

    • 值名称:TCPTimedWaitDelay

    • 值类型:DWORD

    • 值数据:0000001e(30) 

    欢迎关注

  • 相关阅读:
    005. Asp.Net Routing与MVC 之三: 路由在MVC的使用
    004. Asp.Net Routing与MVC 之二: 请求如何激活Controller和Action
    001. Asp.Net Routing与MVC 之(基础知识):URL
    002. Asp.Net Routing与MVC 之(基础知识):HttpModule 与 HttpHandler
    003. Asp.Net Routing与MVC 之一: 请求如何到达MVC
    Factory
    decorator
    Java 单例真的写对了么?
    Dubbo Jackson序列化使用说明
    使用JavaConfig方式配置dubbox
  • 原文地址:https://www.cnblogs.com/zhaixingzhu/p/12569148.html
Copyright © 2020-2023  润新知