【服务器】一次对Close_Wait 状态故障的排查经历

最近接连听说一台线上服务器总是不响应客户端请求。

登录服务器后查询iis状态,发现应用程序池状态变为已停止。

按经验想,重启后应该就ok,第一次遇到也确实起了作用,当时完全没在意,以为是其他人无意把服务关闭了而已。

但是之后几天几乎每天都出现问题,应用程序池再次成为 已停止 状态。这个情况显然有问题。于是开始排查设置。

 

线上环境很简单,iis + API应用,数据库在内网上,没有反向代理。

 

出问题的应用程序池承载了一个基础数据API,查询量极小,数据量也极小,只是因为同事做实现时提过,查询很麻烦,所以我让他同时也检查代码的查询是否过于繁琐产生超出设置上限的资源占用。

但根据同事检查结果,这个情况不存在,数据库查询响应非常快,服务器的资源监控上看相关进程也没有出现明显的资源飙升。因此判断服务端代码应该没有问题。

 

经验路线在这里就走不通了,只能尝试在设置上找原因。 iis对应用程序池的设置里最可能影响服务的是回收策略的设置。为了避免影响其他服务,部署时设置了这个api的专用内存上限到1GB。当然,既然代码检查没有问题,测试运行也没发现资源飙升的情况,回收的专用内存上限应该不会轻易触发。但是还是检查了设置,毕竟从前有同事设置时把1GB给成了100M,除了登录之外执行不了任何请求。

 

最终想到用netstat检查端口情况。起初的怀疑是端口被其他进程无意占用导致问题。

启动netstat后,让测试发了几次请求,顺利看到进程出现在列表,且没有端口冲突,对端地址经查证是来自app。当然,也注意到服务器状态是一堆 Close_Wait.

 

当然我经验少,Close_Wait还真是第一次见。不过既然状态不是Established,这个应该就是问题的原因了。开始查资料,学习Close_Wait状态是什么情况。

 

对于 服务器的连接状态而言,一般有三种比较常见的: Established、 Time_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()。

举一反三,即谁被动关闭,则谁的连接释放代码有问题。

 

但是socket.Close()的调用应当是由web服务器自己完成呀,所以问题还没确定。写api的同事轻描淡写提了一下说代码没关闭链接,但越想越不对。到底什么原因导致没有进行socket.Close(),还需要具体从代码入手。

不过,虽然没有真正搞明白我们遇到的原因,但是原理清楚了,排查的时候还顺手看到客户端的代码存在的问题。后续搞清楚了再更。

 

【1212更新】

终于有空来继续查这个问题了。

前次排查的时候,在没有完全理顺这个原理的情况下认为是客户端(Android)上一段关于登陆请求的超时处理问题。我是被几篇HttpClient的文章干扰了。在那几篇文章里,作者说是因为调用HttpClient组件后,没有对请求资源进行释放(即Response.Body.Dispose()),因此造成了CLOSE_WAIT状态。 但作者没说清楚。就像前文分析的一样,服务端出现CLOSE_WAIT,根本问题一定是服务端的代码有问题。当然,既然排故,就顺便一说。在同事的请求部分代码上,设置了Timeout时间,并且做了不太安全的异常处理:

1 ...
2     Response res = client.newCall(request).execute();
3     if(res.isSuccessful()){
4         return res.body().string();
5     }
6     else{
7         throw new IOException("Unexpected code" + res);
8     }
9 ...

并且这段代码在一组try catch 内部,且仅catch了IOException 【我没细看OKClient的文档,不清楚是否有其他的Ex可能性】

这段代码的问题在于,一定要使用try catch进行流程控制并不合理。此外,response会带有服务端返回的标准Http 状态,因此此处对非200状态的处理过于粗糙,浪费性能。 所以在服务端出现大量CLOSE_WAIT后,这里应该收到大量的500状态,非200只需要正常输出信息并做相应操作即可。

【像Try catch这样的代码,更好的使用方式是用于做应对不可预料的错误,而不是逻辑分支控制。大多数的错误应当由正常的检验代码进行处理。】

但是这部分代码最多给客户端造成问题,不会导致服务端出错。

 

因此,我们转回看服务端问题。

因为出问题的只有Login操作,于是在清楚问题的原理后,同事为Login操作加上了超时的判定。所以我的余下分析只能在修改后的代码上进行。

public void TLogin(string username, string pwd,out string resultJson){using (RtuHmiEntities db = new RtuHmiEntities()){var user = db.Base_Users.Where(x => x.UserCode == username && x.Password == pwd).ToList();if (user.Count() == 0){resultJson = user.ToJSON();return;}var siteList = db.SiteTable.Select(x => new { ID = x.Id, Name = x.SiteName }).ToList();var dtuList = db.DtuTable.Where(x => x.SiteId == null).Select(x => new { ID = x.ID, Name = x.DtuName }).ToList();var regularboxList = db.PressBoxTable.Select(x => new { ID = x.Id, Name = x.BoxName }).ToList();var valveList = db.ValveChamber.Select(x => new { ID = x.Id, Name = x.Name }).ToList();var result = new{Stations = siteList,BusinessUsers = dtuList,Regularboxes = regularboxList,Valverooms = valveList};resultJson = result.ToJSON();                }}

当然,仔细看了登陆操作的业务代码后,我们能发现一些问题。在这个项目上,登陆后需要初始化一些列表类的信息给客户端。这里的操作当然没什么问题。因为同事在参与这个项目时,不止一次向我抱怨数据库设计有问题,查询很繁琐。但是我没有在这个项目上,所以没有具体关注数据库设计的缺陷。

不过从这段代码看,前端需要接受4组信息,分别是 Stations、 BusinessUsers、 RegularBoxes、 Valverooms,数据库给了四张表。这里采用Linq进行查询操作。一般说来,问题不大。实际上,这段代码里查表的部分实际的执行也没有任何明显性能不足的情况。硬挑的话,第一个分支里对空集合转Json反倒会产生不必要的损失。即便如此,在正常情况下,请求执行时间在200ms以内。

既然代码在测试下并没有什么问题,那原因在哪呢?

回想了一下,IIS有一项设置是回收策略的。因为原先遇到过因为回收没有自己定义,几个旧版的很占资源的API还没更新的时候就在回收周期内把服务器资源吃满了,导致其他api无法运行。所以后来会根据测试时的资源情况为线上服务器设置这个回收值。当然,对于一个不怎么复杂的查询类API而言,并不需要多大的资源。于是第一次设置计划给200M的专用内存。不过显然,因为某一两个数据量比较大的API在短时内重复请求,造成了回收,此时登陆测试碰巧遭遇了释放,于是就造成了上述 服务端被动关闭连接,且没有继续向客户端返回FIN包的状态,最终产生了几条CLOSE_WAIT。

 

回想一下,大家遇到的CLOSE_WAIT基本上都是大量出现,而我们遇到的情况只有少量的几条,远没达到客户端测试的请求数量。排查下来看也确实是调试的时候遇到的小概率问题。不过不清楚原理的话,排查起来还是很没头绪的。论理论的必要性。在大多数时候,不需要那么精通理论能做到80分,但是想做到99分甚至更高,就是拼对理论的理解深度了。

 

【Finally,解决方案】

实际上我们为这个问题修正了三个地方。

第一是对客户端代码上做了修改,改进非200请求的反馈方式。

第二是将iis的回收策略修改,提高了专用内存的上限,降低回收时间间隔【看来从实际出发,这样做更有效】

第三,依然对服务端代码进行了修改,对部分请求增加了超时的处理,至于发现的不太利于性能的代码,也会在重构时改进。

当然,对这个问题贡献比较大的是前两条。毕竟出现的主要情况还是服务端被动关闭。

 

这个问题我当然还没研究的太深。如果有错误请务必指出。

 

 

 相关资料:

http://blog.csdn.net/shootyou/article/details/6622226

http://mp.weixin.qq.com/s?__biz=MzI4MjA4ODU0Ng==&mid=402163560&idx=1&sn=5269044286ce1d142cca1b5fed3efab1&3rd=MzA3MDU4NTYzMw==&scene=6#rd

感谢以上优秀的技术文章。

转载于:https://www.cnblogs.com/DannielZhang/p/8000496.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/267952.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

听力阈值计算_中耳功能分析:临床听力测试的重要手段!

点击甘峰听力关注我们中耳功能测试是临床听力学测试中一个重要部分,和常规的气、骨导纯音测试不一样,中耳功能测试从测试的内容看,主要有鼓室声导抗测试、声順值测试、镫骨肌反射阈值测试、咽鼓管功能测试等。从测试的原理看,现代…

大话移动开发之QT-Quick

大话移动开发之QT-Quick 这是一段关于移动开发之QT-Quick开发的音频,由嘉文&鲜橙&李唐三位朋友录制,内容非常丰富,希望大家喜欢。 节目介绍: 如今的智能终端市场风起云涌,移动开发也成了许多开发人员创造梦想的…

go json 自定义_Go语言Echo Web框架9-日志

上一节:Go语言Echo Web框架8-JWT 这一节介绍日志echo自带的日志中间件记录有关每个HTTP请求的信息日志日志中间件用法e.Use(middleware.Logger())样本输出{ "time":"2020-09-13T21:58:07.372015644-08:00", "remote_ip":"::1", &…

C++提取PDF页成BMP图片

背景:之前接了一个小单子,需求就是将PDF转成.tif图片,刚好闲着,就搜了许多资料,最后选择的是PDFium SDK。 1、首先是打开PDF文件, //chPDF为文件路径 FPDF_DOCUMENT pdf_doc FPDF_LoadDocument(chPDF, NU…

Agile in a Flash:重新定义纪律

今天偶遇《Agile in a Flash》一书,第一眼就有想一口气读完的冲动。但好书需要的是慢慢品味,偶尔翻翻也会有不一样的感悟。看过一部分后就有了翻译它的想法,一方面可以让自己慢下来细细研读,另一方面也可以和更多人分享。 专注工作…

cad文字递增快捷键_十年经验总结,100个CAD快捷键。

CAD绘图快捷键命令:1. 圆 > C2. 点 > PO3. 直线 > L4. 圆弧 > A5. 椭圆 > EL6. 表格 > TB7. 矩形 > REC8. 面域 > REG9. 创建块 > B10. 插入块 > I11. 多段线 > PL12. 构造线 > XL13. 图案填充 > H14. 样条曲线 > SPL15.…

【MySql】linux下,设置mysql表名忽略大小写

【障碍再现】 状况描述01:在LINUX下调一个程序经常报出找不到表,但是我明明是建了表的,测试的时候,遇到一些问题,从Windows平台访问虚拟机中的Web应用,经常报出找不到表,但自己明明在数据库中看…

HDOJ1861 游船出租

题目&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1861 代码&#xff1a; #include<stdio.h> #include<stdlib.h> struct info{//记录的数据结构&#xff1b; int id;//船号&#xff1b; char key;//键值&#xff1b; int time;//时间(分钟表示)&#x…

BZOJ 2588 Spoj 10628 Count on a tree | 树上主席树

BZOJ 2588 Count on a tree 题面 求树上两点之间路径上第k大的点权。 题解 一开始看到这道题觉得是树剖&#xff0c;然后又听说是主席树&#xff0c;然后以为是主席树树剖&#xff0c;差点没吓死…… 然后发现&#xff0c;如果每个点都挂一棵主席树&#xff0c;每棵都通过修改父…

会计未来十年发展趋势_谈未来十年会计行业的发展趋势

谈未来十年会计行业的发展方向&#xff0c;会计行业未来十年将变成什么样子?信息化和数据化改变着各行各业&#xff0c;会计行业也不例外&#xff0c;近十年会计行业发生了翻天覆地的变化&#xff0c;10年后&#xff0c;我想还会有巨大的变化。具体变化预想如下&#xff1a;1.…

QT使用Q_OBJECT链接不通过的一种情况

今天在main里自定义继承于QObject的类&#xff0c;添加了Q_OBJECT宏和信号之后&#xff0c;总是链接不通过&#xff0c;提示XXXX::staticMetaObject等等不存在。 后来得知在cpp里定义的Q_OBJECT,需要添加额外步骤才能编译通过。 下面是找到的一段文档&#xff0c;原文&#xff…

实验5: IOS的升级与恢复

实验5: IOS的升级与恢复 实验目的通过本实验可以掌握 1) 掌握IOS 正常的情况下升级IOS2) IOS 丢失的情况下使用TFTP恢复IOS3) IOS 丢失的情况下使用Xmodem恢复IOS 拓扑结构 实验步骤n IOS 正常的情况下升级IOS (TFTP)Router#conf t //进…

element的分页怎么改中文配置_vue想改变element分页样式

我想要把左边靠左 右边pager靠右.el-pagination .btn-next {background: center center no-repeat #fff;background-size: 16px;cursor: pointer;color: #103133;float:right;}.el-pagination .btn-prev {background: center center no-repeat #fff;background-size: 16px;curs…

MYSQL:基础——触发器

MYSQL基础——触发器 引入触发器 什么是触发器 如果你想要某条语句(或某些语句)在事件发生时自动执行。比如&#xff1a; 每当订购一个产品时&#xff0c;都从库存数量中减去订购的数量&#xff1b;无论何时删除一行&#xff0c;都在某个存档表中保留一个副本。就需要用到触发器…

双线macd指标参数最佳设置_常用指标知多少(二)

均线日期的选择种类有很多&#xff0c;一般行情软件常用的均线日期是5日、10日、20日、30日和60日&#xff0c;一般也会默认是这些日期&#xff0c;也有的加上了长线的120日和250日&#xff0c;很好理解&#xff0c;因为每周交易日是5天&#xff0c;所以以倍数做比较。使用海龟…

VI高级命令集锦

1.交换两个字符位置xp2.上下两行调换ddp3.把文件内容反转:g/^/m0/ (未通过)4.上下两行合并 J5.删除所有行 dG6.从当前位置删除到行尾d$7.从当前位置复制到行尾y$ 如果要粘贴到其他地方 p 就可以了由于vi 是建立在 EX 上的 所以 当键入 : 时就来到了 EX 命令状态 8.:ab string s…

图片合成gif_使用在线图片工具处理静态和动态图片的技巧

图片一般分为两种&#xff0c;一种是静态图片&#xff0c;常用的图片格式有jpg&#xff0c;png等。处理静态图片可用用手机自己带的图片处理工具处理&#xff0c;也能够使用线上的在线作图工具来进行操作&#xff0c;比如找图设计&#xff0c;懒设计&#xff0c;稿定设计等设计…

Redis源代码分析之sds, 动态数组

Redis是用C语言编写的。C语言处理字符串一向是个难点。很容易出现内存越界问题。 其它高级语言很容易实现的字符串拼接&#xff0c;在C这里却是百般艰难。因为需要实现计算出字符串所占内存的大小。即不能过大&#xff08;浪费内存&#xff09;&#xff0c;也不能太小&#xff…

kaldi windows安装_kaldi在Windows下的使用

其实不是特别推荐在Windows下使用kaldi&#xff0c;因为在egs下所有的脚本都无法运行&#xff0c;我也是弄了很久才在Windows下配置好kaldi&#xff0c;都一度差点弃坑。就连官方也说There is no commitment to support Windows. The Windows port of Kaldi is targeted at exp…

C#委托的异步调用[转]

本文将主要通过“同步调用”、“异步调用”、“异步回调”三个示例来讲解在用委托执行同一个“加法类”的时候的的区别和利弊。 首先&#xff0c;通过代码定义一个委托和下面三个示例将要调用的方法&#xff1a; /*添加的命名空间using System.Threading;using System.Runtime.…