一、现象:

收到监控服务疯狂告警,发现线上服务 hang 死,但是进程还活着,接收任务的线程【NIO  socket acceptor】死了,请求进不来,查看tcp连接状态,发现有很多 CLOSE_WAIT。

二、第一次分析

1.接到服务告警,第一反应是服务挂了,于是登录生产机器,ps -ef |grep pid ,惊人的发现进程还活着???

2.查看服务hang死前后的detail日志,发现确实还有日志在打印,但是只是一些内存监控的日志,没有生产的流量进来没有发现明显异常,一切都很平静,就那么静静的hang着。

3. 打印线程堆栈信息: jstack pid,发现 【NIO  socket acceptor】线程居然死了

4.查看系统的句柄数,发现只有 8192,记得以前是 65535

5.查看占用的句柄已达近 6000,所以怀疑是句柄数不够导致部分应用假死

6.第一次出事故,为了让服务快速恢复运行,直接./stop.sh,./start.sh应用,重启之后服务正常恢复了

三、疑问?

1.服务中的探活请求还可以间断的访问成功?正常请求访问不通。

2.接收任务的线程【NIO  socket acceptor】怎么死了?

3.是不是因为 NIO socket acceptor挂了,所以请求进不来?导致tcp产生异常的CLOSE_WAIT状态?

4.CLOSE_WAIT产生原因?

5.是不是BS3框架的bug?

6.是不是Nginx的问题?

四、CLOSE_WAIT

首先不用看是客户端还是服务端,只有被动关闭连接的才会进入 CLOSE_WAIT 状态

通过原理图,我们知道了CLOSE_WAIT是被动关闭的状态。什么意思呢?比如客户端发了个请求,正常情况下是会收到服务器响应一个状态的,即Response。当客户端读取了这个返回后,会主动告诉服务器收到了,关闭连接。

由于是客户端发起关闭连接的请求,在TCP协议下双方需要通过四个包的互发完成双向确认工作,才能最终关闭这个连接。

客户端要求关闭,此时客户端状态为 FIN_WAIT_1,同时向服务器发送了 FIN 包,服务器状态变更为CLOSE_WAIT;

当然,服务器需要对收到FIN包向客户端确认,于是服务器向客户端发送了 ACK 包,客户端因此变更状态为FIN_WAIT_2;

服务器处理了这个确认后,再次主动向客户端发送FIN包,同时自己状态变更为LAST_ACK,收到来自服务器FIN包的客户端也将自己状态变更为TIME_WAIT;

最后一步,客户端会对来自服务器的FIN包回复确认,服务器收到该ACK包后,将自己状态置为CLOSED,如此,整个关闭过程结束。

简单说就是,客户端 -》 服务器,我要关闭,服务器回复OK,并开始处理后续;服务器后续处理好后,再告诉客户端我可以关闭了,客户端确认,服务端关闭。

所以,出现CLOSE_WAIT状态的原因是,服务器一端因故没有向客户端发出FIN包,即服务端的LAST_ACK -- FIN -->客户端这步没能执行。

因此,看到CLOSE_WAIT状态后,那么可以确定服务器没有执行后续动作,即调用socket.Close()。

翻阅参考了网上很多CLOSE_WAIT的案例,很多博主都说是代码书写问题,根据CLOSE_WAIT的产生原理,我们重新整理了一下整个事件。

五、复现

为了更好的分析问题,如果能复现问题那是最好的了。于是我们根据事故的现象以及我们的猜想,在测试机上进行了一些复现尝试。

系统参数:ulimit -n:1024

1.客户端设置read time out 时间为 3s,服务端随机睡眠 5-10s,造成客户端主动关闭连接,服务端被动关闭连接的现象,200 个线程循环压测。

2.同样的操作,请求改为Nginx跳转的方式进行压测

3.客户端注释掉socket.close()代码,再次测试上述两种情况

结果:没有出现 CLOSE_WAIT 的现象,lsof -n | wc -l 当前的句柄占用高达 8000 多???难道这个不是查看当前系统占用的句柄数命令?

六、再现

重启恢复之后,没有过多长时间,同一台服务器上的另一个应用服务也出现了类似的状况。之后的十来天里,服务接二连三的hang死,有的服务重启之后,最快的一个小时内再次出现了同样的问题。忍无可忍,决心一定要解开它的面纱,以单点服务运行着,保留案发现场。

七、思考

1.出问题的应用都在那两台服务器上,是否是某个系统参数的影响?

2.刚开始认为可能是 BS3 框架存在的 bug,导致服务 hang 死,但是也有没有使用BS3框架的应用也出现了问题,所以到底是什么呢?

3.这段时间,服务器配置是否有过调整?

4.是否跟近期新增了几个应用服务有关?

八、填坑

1.打印服务堆栈信息,情况和之前的一样,nio socket acceptor 线程挂了

2.查看 tcp 连接状态 【netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'】  ,依然是大量的 CLOSE_WAIT

3.查看hadoop用户下的线程数     【ps -eLF | grep hadoop | wc -l 】,结果是 1024 个

4.查看系统最大可开启的线程数   【ulimit -u】 , 结果为 1024

5.线程数已达上限,导致创建不了新的线程处理任务。

6.修改最大可开启线程数为 10240 之后,服务到现在为止没有出现过问题

7.近期服务器上新增了几个应用,而每个应用服务都会在运行期间开启上百个线程,导致线程数不够用,从而导致 CLOSE_WAIT,从而使 【nio socket acceptor】 线程起不来

8.之前一直以为 【nio socket acceptor】 是因,现在才知道这是果,超级大反转啊。

九、补充

1.上面说的探活请求可以间断的请求成功,这是什么鬼?

答:原因是探活应用采用的是长连接的请求方式,服务 hang 死的时候还有长链接连着,所以有请求成功的,没有请求成功的说明是在新建长链接的时候失败了

十、总结

1.线上故障,在可以保持可用性的情况下,一定要保留案发现场,方便后续问题的排查。

2.以往只知道CPU资源是有限的,现在才知道,原来可开启的最大线程数也是有限制的。

3.故障排查要有清晰的逻辑,不然也还是很难找到问题所在的原因。

最后附上监控 tcp CLOSE_WAIT 的脚本

warnNum=60
while true
doa=`netstat -n  | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' | grep CLOSE_WAIT | cut -d ' ' -f 2`if [ $a -ge $warnNum ] then echo `date +%m%d:%H:%M:%S`"连接未释放的超过$warnNum个,已达$a个,请查看5.51"echo "发送微信告警"   curl -d "连接未释放的超过'$warnNum'个,已达'$a'个!请检查服务器aa.b.c.d" http://xxx/xxx/xxxfiecho $a sleep 10
done

参考文章:

https://www.cnblogs.com/DannielZhang/p/8000496.html

记一次生产上的 CLOSE_WAIT相关推荐

  1. 悬崖边上的舞者,记7.2生产数据库灾难事件

    悬崖边上的舞者,记7.2生产数据库灾难事件 作者:张子良 版权所有,转载请注明出处 引子:出事了 7月2日是一个难得的大晴天,一段时间以来桂林一直在下雨,一直下,害的我减肥的计划一再的泡汤,因为下雨每 ...

  2. 记一次生产数据库事故

    记一次生产数据库事故 事故起因 事故故事 事故现场 事故起因 最后在做报表,报表的数据产生是直接在只读库上面进行的.但因数据量大需要对表做优化,现行优化方式为简单粗暴的加索引. 另外说明一数据库用的是 ...

  3. 记一次线上环境 redis偶尔连接超时报错 解决

    记一次线上环境 redis偶尔连接超时报错 解决 贴出本地控制台日志 说实话,很痛苦,跟进很久了,一直认为的jvm程序所使用的配置的连接池框架问题 因为程序为 springboot 2 spring ...

  4. 生产上如何设置线程池参数?拒绝策略怎么配?|| Executors 中 JDK 给你提供了,为什么不用??

    生产上如何设置线程池参数?拒绝策略怎么配?

  5. 生产上第一使用线程池后的总结与反思

    生产上与 esb 交互时,因为系统后台造数使得 esb 接收响应报文超时.先将造数逻辑修改成线程池异步调用.第一次使用,记录一下学习的历程. [1]Java向多线程中传递参数的三种方法 https:/ ...

  6. mysql 测试快生产慢_生产上MySQL慢查询优化实战,SQL优化实战

    之前看了饿了么团队写的一篇博客:等等!这两个 Spring-RabbitMQ 的坑我们已经替你踩了.深受启发,一定要取个能吸引读者眼球的标题,当然除了响当当的标题以外,内容也要是干货.为什么会想取这样 ...

  7. 生产上完成TopN统计流程

    背景 现有城市信息和产品信息两张表在MySQL中,另外有用户点击产品日志以文本形式存在hdfs上,现要求统计每个个城市区域下点击量前三的产品名,具体信息见下方. mysql> show tabl ...

  8. 记一次线上coredump事故

    转自:http://www.likecs.com/show-16439.html 记一次线上coredump事故 1.事故背景 上周三凌晨,我负责的某个模块在多台机器上连续发生coredump,幸好发 ...

  9. 记一次生产环境脚本入侵检测与报警案例(检测特定目录被改动,自动报警)

    需求 : 特定目录,改动之后,自动报警. 转载来源 : 记一次生产环境脚本入侵检测与报警案例(简易版入侵检测系统) : http://www.safebase.cn/article-259102-1. ...

最新文章

  1. centos lamp 连接mysql_centOS下lamp安装
  2. 简述JavaME,JavaSE,JavaEE
  3. 【TCP传输数据-键盘录入】
  4. ldap基本dn_LDAP 中 DN CN DC OU
  5. java怎样生成32位全是整形的主键_用java生成32位全球唯一的id编号
  6. 第八章:在Spark集群上掌握比较重要的图操作之Property Operators(1)
  7. NGUI_2.6.3_系列教程六(序列帧动画)
  8. 3分钟了解计算机基础知识,你对电脑还一无所知?3分钟带你全面了解电脑基础知识...
  9. winform利用html开发,Winform开发框架之HTML编辑控件介绍
  10. 2017年西安邮电大学第十二届数学建模竞赛B题论文
  11. 2021年PMP考试模拟题3(含答案)
  12. H5唤起APP指南(附开源唤端库)
  13. java的框架gwt介绍_GWT Portlets
  14. 英语四级考试在即,这几个超有用的App赶紧用起来,顺利考过四级
  15. 重生之我是赏金猎人-SRC漏洞挖掘(十三)-攻防对抗/梦中绝杀X脖代理商
  16. 全网最全-探花交友项目-面试总结-简历优化
  17. 线性代数中满足乘法交换律的运算-行列式与迹
  18. 【第12天】给定一个X进制数字A,请你把它转换为十进制打印 | 进制转换
  19. CF711C三维DP
  20. mkdir命令(创建目录(文件夹))

热门文章

  1. 详尽JavaWeb学习—01
  2. 与人交往哪些心态不行
  3. PHPxiu视频互动系统
  4. Java 微信公众号开发(一) 介入微信
  5. Win7资源管理器崩溃
  6. 如何提升机器人的回环检测能力?
  7. 发送ZPL指令到斑马打印机,并监控打印成功或者失败的状态信息
  8. github仓库,大仓库套小仓库,小仓库如何同步-submodule -双层 git git-仓库-套娃
  9. Flutter 强制获取焦点的问题
  10. 小互联网创业公司“宫斗”大戏