美文网首页程序员我爱编程
Apache CPU无故100%的查错过程

Apache CPU无故100%的查错过程

作者: 唐九十九藏 | 来源:发表于2018-04-01 23:18 被阅读540次

    公司在经过一周时间开发与测试,一款电商小程序终于是审核通过上架了,但是老板在使用过程中,发现小程序使用着使用着,数据就加载不过来了,前端界面显示网络不给力。

    小程序的后台是部署在阿里云的,配置如下:

    操作系统:window server 2012 R2

    服务器: apache 2.4.23

    脚本:PHP 5.6.25

    数据库:MySQL 5.6.14

    安装的是集成软件:WAMP 3.0.6 64bit

    在接到老板和开发小程序的同事反馈后,我立马远程登录到服务器中,打开任务管理器,看到如下情景:

    CPU占用几乎达到了100%,但是内存却正常,而且数据库连接也是正常的。

    我当时想到了第一种可能,是PHP的某段代码出现了死循环,导CPU陷入无限工作之中,所以才会出现CPU100%,而其他如数据库和内存正常的现象。

    但是,很快,我就排除了这种可能,因为这个CPU100%不是一直存在的,一打开小程序的时候并没有,CPU很正常,一切都很正常,我浏览首页,分类页,商品详情页,都没问题。

    只有我在购物车页里快速的加入某商品时,CPU才会很快达到98%,而且最奇怪的是,只要我等上那么五分钟,CPU又会恢复正常。这种情况就说明不是某个代码出现死循环了,因为一旦出现死循环,CPU是不会自己恢复正常的。

    于是,我想到了第二种可能,是加入购物车这条接口的后台执行时间太长了,当短时间内进行大量请求的时候,CPU被完全占用,然后就瘫痪了,于是我让前端同事将加入购物车这个动作限制一下,不让客户频繁的点击加入购物车。

    情况好了那么一点,但是我总觉得哪里不对劲,我一个人就可以把服务器给挤崩溃了?那随着用户递增,那不是完犊子了?

    于是我去Google里翻阅各种资料,发现apache提供了一个模块mod_status,启用这个模块就可以监控到apache的连接数,我开始按照教程做:

    1.先到httpd.conf里找到下面这个模块,把它前面的#去掉

    LoadModule status_module modules/mod_status.so

    2.配置mod_status

    <location /server-status>

        SetHandler server-status

        Require all granted

        Order Deny,Allow

    </location>

    3.重启apache,访问http://localhost/server-status?refresh=1,refresh表示一秒刷新一次。

    我用mod_status监控了几次,最终发现,在同时又30到40条请求的时候,服务器就崩溃了,我心里骂娘,莫非后台同事在加入购物这个接口里把整个数据库遍历了一次?于是我将该接口的最顶端直接返回一个结果,数据库我都不去查询。

    但是,就算是这样,当并发请求达到40条以上,同样是崩溃了。

    我郁闷,只能继续去Google上翻阅资料,翻着翻着,看到有大神说通过设置apache的timeout可以提高并发量,我心里想,你不是执行时间长吗?我给你加限制,到时间了处理不完也抛弃掉你。

    我按照网上的教程,找到apache的httpd-default.conf文件,在该文件中,我找到了timeout配置,wamp给他的默认值是60,代表60秒的意思,于是我直接给他设成了5秒,最后还要在httpd.conf文件里将

    Include conf/extra/httpd-default.conf

    前面的#号去掉,这样httpd-default里的配置才会起作用。

    重启服务后,又开始测试,天,情况还是一样,40条请求后就崩溃,timeout没起作用?

    后来一查,才知道timeout并不是指一条HTTP请求处理的时间,而是诸如服务器发送TCP包时间,HTTP请求时间等等,也就是说,只要请求进入了脚本执行阶段,这个时间是不受timeout控制的。timeout误解

    到这里,我都懵逼了,毕竟我不是大神,我开始浏览器起httpd-default.conf和httdp.conf中的配置字段配合着查询apache的知识。

    原来apache有很多种工作模式Apache的三种工作模式及相关配置 - CSDN博客,并且apache专门为window系统开发了一个专门的模式:mpm_winnt_module,其实mpm_winnt_module就是works模式,window上使用该模式的基本原因是因为window系统里的进程是一个开销很大的东西。

    同时,我还查找了mpm_winnt_module模式启动时,只会启动两个进程,一个监听进程,一个工作进程。

    工作进程里会创建一定量的线程,这个数量可以通过配置文件设置的。

    而监听进程是监视工作进程的,一旦发现工作进程有问题,可以进行查杀和重启工作进程。

    所以,为什么window任务管理器里会有两个httpd.exe进程的原因就在这里了。

    抱着死马当活马医的心理,我找到了mpm_winnt_module的配置代码,进行了如下设置,

    <IfModule mpm_winnt_module>

        ThreadsPerChild 250    #这个指示了工作线程将启动多少个线程

        MaxRequestsPerChild 5000   #这个指示了当请超过了该数量,监控进程就会杀死当前的工作进程,并重启一个新的工作进程

    </IfModule>

    然而,无论,我设置多大,或者多小,40条请求时,apache依然崩溃了。。。。

    这个时候的我,知道了工作进程里有很多线程,而且处理请求的正是这些线程,我就在想,如果我知道了哪条线程有问题,然后通过那条有问题的线程,再定位到有问题的代码不就完美了?

    我又开始了Google,看到了大家都在推崇微软出的调试神器windbg,于是满怀希望的下载下来,打开捣鼓了半天,发现不会用!!!上网查了半天,云里雾里的,还是不会用,不过我知道,这个工具肯定很牛逼,可以debug到window的内核,但是我不会用,尴尬。

    不过幸好,我在查资料的过程中,发现了一位大神推荐另一个神器:Process Explorer 下载地址

    下载下来之后,不用按装,根据自己电脑的位数,打开软件,界面如图:

    找到httpd.exe,双击httpd.exe(父进程,也就是监听进程)下面的httpd.exe(子进程,也就是工作进程),在新面板中选择Threads面板,可以看到该面板显示了该进程下面的所有线程。

    点击按CPU进行排序之后,我又测试了好几遍,发现了会有几条线程长期占用着CPU,一直不释放,找到那条线程,双击,进入线程栈,所谓线程栈就是该线程的调用过程,某一条出问题的线程栈如图:

    说实话,这些东西我一个都看不懂,我就发现了图中红圈画的异常,该线程一直在报某个错,我看到前面的php_xdebug-2.4.1-5.6-vc11-x86_64.dll+0x562e,还以为是我开了xdebug导致的错误,于是我打算去关闭掉,一查才知道,服务器根本就没开xdebug。

    接着又看到php5ts.dll!zend_execute+0x4c7,我看不懂,但猜测应该和PHP有关,于是突然想起wamp有一个记录PHP错误的日志,跑到那里一看,果然有一个错误:

    说某个文件无法写入,也就是写入函数报错了,妈的,原来是PHP在写缓存的时候,存储缓存的文件夹会被后入的请求删除掉,于是会不断有请求报错,而且,由于写了报错重新尝试机制,于是PHP代码在原地不断的尝试写入,又不断的报错,所以CPU就被占用了。

    唉,绕了一大圈,原来问题就在眼前记录着,不过,值得庆幸的是,这个过程中学到了许多。

    1. apache的工作模式(进程和线程)

    2.window的调用工具(windbg,Process Explorer,这两个我都要学会的)

    3.apache的一些配置(线程数量,请求最大值等等,我回头会写一遍关于apache配置的博文)

    目标:

    我要知道有什么工具可以显示出线程中代码的执行流程,调用的函数,调用的方法,那么当遇到这些问题的时候就可以很快的定位到出问题的代码了。

    一个每日更新的干货公众号

    相关文章

      网友评论

        本文标题:Apache CPU无故100%的查错过程

        本文链接:https://www.haomeiwen.com/subject/whgacftx.html