服务端大量CLOSE_WAIT问题的解决

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:

今天在运行服务器的时候发现一个问题,问题的表现是客户端一直在请求,但是返回给客户端的信息是异常,服务端压根没有收到请求,查看了一下配置信息没有错误,首先查看了一下是不是服务器的连接已经满了,打开n …

今天在运行服务器的时候发现一个问题,问题的表现是客户端一直在请求,但是返回给客户端的信息是异常,服务端压根没有收到请求,查看了一下配置信息没有错误,首先查看了一下是不是服务器的连接已经满了,打开netstat命令发现服务器的连接有大 量的CLOSEWAIT状态的socket,没怎么遇到这个问题,开始还真有段懵了,第一反应就是是不是客户端的问题(是不是出问题的第一反应都是别人 的问题),但是马上补充了一下socket状态机的知识,发现这个状态是由于客户端关闭了socket连接,发送了FIN报文,服务端也发送了ACK报 文,此时客户端处于FINWAIT2状态,服务端处于CLOSEWAIT状态,如下图:

33d09c9edf4607f5fef094795d84099a92d1441f

可以看出,出现问题的原因是由于我这边没有发送第二个FIN报文导致的,分明是我的问题啊,为什么服务器没有发送FIN报文呢?我的服务器使用的是嵌入 式的jetty,连接管理应该都是它帮我管理的,重启了一下服务器发现服务器的CLOSE_WAIT开始的时候没有出现,之后逐渐的上升,貌似随着请求的 数量逐渐增长的,而我这边的日志也非常奇怪,我会在收到请求的时候打印日志,然后在执行完毕的时候输出一个accesslog信息,发现日志中有入口的请 求日志,但是accessLog没有增长,于是单步调试了一下,发现了问题:一个servlet的执行走到主流程就走不下去了,阻塞在数据库访问那一步 上,具体表现就是获取不到数据库连接!

查看了一下代码,发现原来是自己创建连接,执行sql,完成之后没有关闭连接,OMG,这么愚蠢的错误,于是在所有的数据库操作的最后加上如下的代码:

 
  1. finally {

  2. DbUtils.closeQuietly(conn);

  3. }

好了,既然问题能够解决了,现在回头来思考一下问题产生的具体步骤:首先,我这边的大部分请求都需要查询数据库,我的数据库连接池设置的最大连接数是 100,所以每一个请求创建了一个连接,等到100个请求就把连接池占满了,但是处理servlet的那个线程并没有释放这个连接,于是接下来的请求再去 创建数据库连接的时候就会一直阻塞在那里,这里我所用的是DBCP作为连接池的,它的实现好像是使用apache的objectPool来实现的,如果没 有可用的连接对象会导致线程等待,好了,servlet由于得不到数据库连接而阻塞了,这个客户端的请求就一直等待,客户端使用httpclient设置 了5s的请求超时时间,那么超时之后就会抛出异常,关闭连接,关闭连接导致客户端发送了FIN报文,我这边的TCP/IP返回了ACK报文,但是由于处理 请求的线程还处于阻塞的状态,所以当前的连接状态时CLOSE_WAIT。

警示:

 ●  代码一定要规范,尤其是在写一些关于自愿申请的部分,一定要在写函数之前写上注释告诉自己别忘了释放资源。
 ●  数据库连接和访问要设置超时时间,这点避免阻塞。

 ●  服务器的线程数也需要设置,使得问题尽可能的出现。


原文发布时间为:2018-11-14

本文作者:HARRIES

本文来自云栖社区合作伙伴“Java杂记”,了解相关信息可以关注“Java杂记”。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
5月前
|
网络协议 Linux API
Linux网络编程:shutdown() 与 close() 函数详解:剖析 shutdown()、close() 函数的实现原理、参数说明和使用技巧
Linux网络编程:shutdown() 与 close() 函数详解:剖析 shutdown()、close() 函数的实现原理、参数说明和使用技巧
406 0
|
5月前
|
Windows
如何在关闭socket连接的时候跳过TIME_WAIT的等待状态
如何在关闭socket连接的时候跳过TIME_WAIT的等待状态
|
11月前
|
消息中间件 网络协议 Java
深入剖析阻塞式socket的timeout
深入剖析阻塞式socket的timeout
|
网络协议 应用服务中间件
服务器CLOSE_WAIT请求太多的问题
服务器CLOSE_WAIT请求太多的问题
559 0
|
数据库
为socket的recv/send设置超时
为socket的recv/send设置超时
254 0
ssh2 Connection .connect()方法抛出连接过早关闭异常
ssh2 Connection .connect()方法抛出连接过早关闭异常
ssh2 Connection .connect()方法抛出连接过早关闭异常
|
监控
实践解读CLOSE_WAIT和TIME_WAIT
实践解读CLOSE_WAIT和TIME_WAIT
355 0
实践解读CLOSE_WAIT和TIME_WAIT
|
弹性计算 网络协议 Java
记一次time_wait & close_wait的讨论总结
记一次time_wait & close_wait的讨论总结
记一次time_wait & close_wait的讨论总结
|
数据采集 网络协议
一次TIME_WAIT和CLOSE_WAIT故障和解决办法
昨天解决了一个curl调用错误导致的服务器异常,具体过程如下: 里头的分析过程有提到,通过查看服务器网络状态检测到服务器有大量的CLOSE_WAIT的状态。   在服务器的日常维护过程中,会经常用到下面的命令:   它会显示例如下面的信息: TIME_WAIT 814CLOSE_WAIT 1FIN_WAIT1 1ESTABLISHED 634SYN_RECV 2LAST_ACK 1 常用的三个状态是:ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。
2696 0