记一次web服务器内存爆满100%,结束进程后又马上100%的解决过程。

事情起因:由于一次活动通知,要求全市家长上微信公众号参加视力自测(活动未通知开发部),导致短时间内访问量激增,服务器内存达到100%,结束进程,重启服务器后都不行,马上又升到100%。

服务器配置:2台web服务器 8C16G,1台数据库服务器16C32G,Windows Server 2012, IIS7

处理过程:

1、第一阶段

因为当天下午发布过代码,所以首先想到的会不会是发布新功能导致的,所以赶紧将功能回滚,但是内存仍然很高,排除新功能发布引起的。此时访问人数还不是很多,内存大致在80-90%上下,用户访问只是感觉很慢,页面还是可以进去。

于是怀疑是不是服务器运行时间太久,导致服务器性能下降。所以将所有服务先迁移至另外一台服务器上,然后重启了服务器,还是不行,新服务器和原来的服务器内存都很高,两台服务器通过负载均衡同时对外服务两台内存都很高。

开始百度各种文章,几乎千篇一律,都说要设置应用程序池的回收机制,比如定时回收,内存超过多少G就回收,但是这些方法都没有解决根本问题,我想知道为什么内存会持续升高,而不是升高以后就回收程序池。但是我还是按照百度

文章里的办法设置了超过8G就回收,然而并没有用,当进程超过8G以后,原进程不会马上被回收掉(回收需要时间),但是会马上出现另一个一模一样的进程(只是PID不同),新进程马上又超过8G,马上又会出现第三个进程,可能此时

第一个超过8G的进程才会被完全回收,但是整体内存占用率并没有减少,甚至有时候会升高,达到99%。然后就是不停的新增进程,回收进程,如此反复十几分钟以后直接导致网站崩溃(程序池直接停止了)。

 

2、第二阶段

求助于腾讯云工程师,对方工程师远程到服务器及控制台查看了各项监控指标,指出“入网带宽异常,超过了每秒100M,一个正常restful 请求都是几kb, 100M 等于十万倍了,可能是有CC攻击”。然后让我查看IIS日志,查看是否存在可疑的IP和UA头。

于是开始查看对应站点的IIS日志,发现今天的日志体量是之前的20多倍,之前平均每天的日志大概在5-7M左右,但是今天的日志截止到下午6点已经有160M(到晚上12点有250M)。然后开始翻看这些日志,IP全部都是负载均衡的IP,所以毫无价值。

UA头翻看了大几百条也全都是正常的。然后腾讯工程师让我装waf防火墙,带有防CC攻击功能,然后下线了。至此,该问题毫无进展,只能继续自己排查。

 

 

3、第三阶段

此时已是晚上7点多,家长访问微信的高峰期,服务器内存几乎全程在99%,网站已经打不开了,手动结束进程,大概2-3分钟就又99%,只能自己排查原因和优化代码了。首先,还是要从IIS日志着手,看看用户访问最多的几个页面和请求是哪些,

最耗时的请求有哪些,IP分布情况等等,有了这些数据才知道要从哪里下手。所以查看原始日志文件是不现实的,这里要感谢我的同事王超,帮我装了一个IIS日志分析工具LogParser和LogParser Studio,两个都是微软自己开发的,语法同SQL类似,

可以执行各种查询和统计。下载地址:LogParser(http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=24659),LogParser Studio(https://techcommunity.microsoft.com/t5/exchange-team-blog/introducing-log-parser-studio/ba-p/601131)。通过该工具,我分别查看了访问最多的页面,耗时最多的请求,以及外网IP,同时下午6点多该活动也通知到开发部,所以初步排除CC攻击的可能性,应该就是访问量过大导致的。

 

可以看到访问量最大的页面和请求分别是OAuth2、WeMsg、StudentCenter、VisionTest和SF20220113。耗时较多的请求则面很广,几乎所有请求都耗时,这也可以理解,毕竟服务器内存100%了,所有请求都很慢。所以我们还是先从访问量最大的

几个页面分析。首先,OAuth2是用于微信网页授权,同code换openid的请求,每个访问用户首先都要通过这个请求获取到openid,拿到openid后就跳转到其他页面,所以该请求执行速度很快,且没有优化空间。WeMsg是统一报错页面,如404等页面,

本身没有任何逻辑,所以问题也不在这个页面。StudentCenter是家长首页,会显示绑定的信息及菜单。VisionTest就是本次通知的活动页面,页面首先获取绑定的用户信息,中间的测试过程都是js前端完成的,最后提交结果保存到数据库。SF20220113

是家长课堂页面,里面有一个菜单链接跳转到活动页面,全市下发的通知里面参加流程是先进入家长课堂,再进入测试页面,所以这个页面访问量也比较大,但是用户最终的目标页面是VisionTest,即活动页面。所以,我们需要从家长首页和活动页面进行

代码优化。因为是web服务器内存爆满,所以我先想到的就是取消了一些缓存罗姐,然后屏蔽了一些不必要的查询功能,因为这两个页面的逻辑都非常简单,所以可优化的空间其实并不大。做完这些以后发布网站,发现问题并没有解决,内存依旧100%。

 

此时已是晚上10点左右,电话被各种打爆,都是问活动页面进不去,网站打不开等等。代码优化暂时起不到作用,问题也没有头绪,只能先将活动页面屏蔽,不然整个微信都进不去,影响到其他功能的使用。于是我加了一个跳转,所有访问活动页面都提示

“当前访问人数过多,请稍后尝试”,果然内存马上就降下来了。接着我加了一个限流的功能,让一部分用户可以访问活动页面,于是写了一个令牌桶算法,限制每分钟允许150人访问,超过150人就会提示访问人数过多,内存在50%-70%之间跳动,算是临时

性的解决了问题。但是根本问题还未解决。

4、第四阶段

梦中阶段。晚上睡觉做梦想的都是问题出在哪里。突然灵光一闪,发现哪里不对劲,因为活动页面和首页的后台逻辑几乎一样,都是查询当前openid绑定的用户信息,然后显示到页面上,活动页面多一个保存结果,但是保存是调用的第三方接口,也不是自己

保存,所以两个页面几乎是一样的,为什么屏蔽活动页面以后内存就降下来了?用户其实仍在大量访问首页(首页并未屏蔽),而且从IIS日志看首页的访问量比活动页面更大,如果代码有问题,那么首先挂的应该是首页才对,为什么首页没有挂,反而是活动

页面挂了,这一点很奇怪。于是脑海中开始对比两个页面的源代码,只有一个地方不同,那就是首页是用openid去查询用户绑定信息,而活动页面是用的unionid查询(因为活动页面还在其他关联的公众号和小程序里共用),这是唯一的差别,难道用unionid查询

效率会很慢吗?我首先想到的是数据库索引,确实openid建立了索引,unionid没有建索引,索引虽然可以提高查询效率,但是也不至于差别这么大吧,一个内存只有几百M,一个内存十几个G都不够?但是这是目前唯一的差别的,心里想的是明天一早就把unionid

的索引加上看看。

5、第五阶段

一早来到公司,发现服务器内存还好,仍在50-70%直接跳动,页面还能进去。开始准备加索引,中途就跟同事王超说了我的怀疑点,两个页面一样的逻辑,差别只在openid和unionid上,为什么内存消耗差别这么大。突然他的一句话又点醒了我,他说他做的页面

也是用unionid查询,有时候会出现不是自己绑定的用户,而且列表非常长。我说不可能啊,不是自己绑定的用户,怎么可能被查出来呢?但是突然转念一想,只有一种情况会出现他说的问题,那就是unionid为空或者为null的时候,因为unionid机制是今年才加的,

很多老用户只有openid,没有unionid,虽然系统会自动补齐用户的unionid,但是数据库仍然存在大量为空的unionid,于是我查询了一下为空的unionid,一共有110w条,这是一个非常可怕的数字,也就是说一旦用空unionid去查询用户关系,会查询出110w条记录,

那内存不爆满才怪,但是为什么会出现为空的unionid呢?因为unionid和openid一样,也是在微信授权的时候获取的,用户通过正常渠道unionid是一定不会为空的。为了知道到底是否存在unionid为空的请求,我再次借助了LogParser工具,果然发现存在unionid为

空的请求,此时心中的疑团一大部分解开了,但是为了证实unionid为空会导致内存爆满,我决定在本地做测试,在VS里打开性能监听工具,然后将日志中的URL复制出来,发现我的本地内存确实在不停的上涨!!!服务器内存爆满的原因终于找到了。问题找到

了就好解决了,所有用unionid查询的地方都先判断unionid是否为空,为空则不查询直接跳出逻辑;其次,将活动页面的查询改为openid查询。修改发布后,内存基本维持为360M左右,整体占用率也只有20%了。

 

还剩下最后一个问题,就是为什么会存在unionid为空的情况。于是开始开始检查代码,发现是在 SF20220113页面,这个页面上有一个跳转到活动页面的链接,参数只有openid,没有unionid,应该是系统引入unionid机制时改漏了这个页面,导致从这个页面跳转

到活动页面时unionid为空,刚好通知里写的步骤又是从这个页面进去,才导致大量消耗内存的查询,进而导致服务器内存爆满。

 

 

结束语

至此,服务器内存100%的问题终于是解决了。解决问题还是要依靠强大的分析工具,否则没有方向,不知从哪里下手。其次,对问题要学会分析,找出差异点来,用排除法层层深入解析。最后,需要对代码非常熟悉,以及各方面知识的综合

能力。

 

原文地址:http://www.cnblogs.com/boyanga/p/16874561.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性