没有实际的操作设备和条件,只能看文章来体验。文章主要是通过观察实例来说明close_wait状态的问题,一般导致close_wait状态都不是有意的,而是操作不注意就会导致此问题的出现。所以在代码书写上一定要确保不会出现问题。
事件:socket数量从某个时间点开时不断上涨,重启后过一会又开始上涨,每次达到峰值的事件不断缩小。
出现问题后,首先要进行分析推断、然后验证、最后定位修改。根据当时的表现是分别进行了以下猜想。基础架构图如图所示:
推断一
socket 资源被不断打满,并且之前从未出现过,今日突然出现,怀疑是不是请求量太大压垮服务
经过查看实时 qps 后,放弃该想法,虽然量有增加,但依然在服务器承受范围(远远未达到压测的基准值)。
推断二
两台机器故障是同时发生,重启一台,另外一台也会得到缓解,作为独立部署在两个集群的服务非常诡异
有了上面的的依据,推出的结果是肯定是该服务依赖的底层资源除了问题,要不然不可能独立集群的服务同时出问题。
由于监控显示是 socket 问题,因此通过 netstat 命令查看了当前tcp链接的情况(本地测试,线上实际值大的多)
/go/src/hello # netstat -na | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
LISTEN 2
CLOSE_WAIT 23 # 非常异常
TIME_WAIT 1
推断出现这种情况可能的原因有以下几种:
1、负载均衡器异常退出了,
这基本是不可能的,如果负载均衡器出问题了,那么问题大多出现是大面积的故障,而不但单单是一个服务,所以排除这个选项
2、MySQL负载均衡器的超时设置的太短了,导致业务代码还没有处理完,MySQL负载均衡器就关闭tcp连接了
这也不太可能,因为这个服务并没有什么耗时操作,当然还是去检查了负载均衡器的配置,设置的是60s。
3、代码问题,MySQL连接无法释放
目前看起来应该是代码质量问题,加之本次数据有异常,触发到了以前某个没有测试到的点,目前看起来很有可能是这个原因。
上面我们推断代码中没有释放mysql连接。无非就是:
1.确实没有调用close
2.有耗时操作(火焰图可以非常明显看到),导致超时了
3.mysql的事务没有正确处理,例如:rollback 或者 commit。
通过代码分析出在return false前没有进行回滚,导致我释放不了mysql连接,无法调用close占用大量文件描述符。