我有一个服务器,让我头痛。 它拥有几个网站:这些都是基于PHP或基于Java。 我有一个设置,使用Apache2 + suPhp的PHP网站,和apache2 +的mod_proxy + Apache的Tomcat的Java应用程序。
在过去的几个星期里我看到一些奇怪的行为。 有时,我会得到一个单一的httpd进程,达到30-40%cpu,超过70%的内存。 我没有看到任何PHP或Java进程占用额外的资源,所以我(天真地)认为这个问题是不相关的PHP或Java代码。 这些高峰似乎随机发生在随机的时间和随机的时间间隔; 有时每天多次,其他时间整整一周都没有发生。
我注意到的另一个奇怪的事情是,当我手动kill -9
正在执行的httpd进程时,另一个httpd进程会在几秒钟内popup,并开始占用大量的内存和CPU。 我可以重复几次,直到它自己停止发生:/
所以,我其实有几个问题:
UPDATE
最近我发现,造成这个烂摊子的请求来自googlebot。 这是消耗所有可用的mem和cpu的进程的lsof
输出摘录:
httpd 18588 nobody 37u IPv6 96675092 TCP myhost.com:http->crawl-66-249-76-96.googlebot.com:56730 (ESTABLISHED)
我设置了mod_security来logging来自我的<VirtualHost>
中googlebots似乎使用的IP范围的所有来自这个规则的请求:
SecRule REMOTE_ADDR "@ipMatch 66.249.76.0/24" phase:1,id:1,auditlog,allow
我这样离开了服务器一段时间。 在这段时间内,httpd进程被刺激了好几次,到了OOM守护进程开始查杀进程(httpd,java,甚至现在不时地closuresmysql)的程度。 然后,我提取了所有被googlebot击中的url,并创build了一个curl所有这些url的脚本,希望能够使httpd进程飙升,从而find导致这些问题的请求。
不幸的是,这并没有发生 – 所有的请求都很快返回,而cpu和内存使用情况远不及Googlebot访问服务器时的情况。
所以我认为有两种可能性:
问题是由于特定的HTTP标头。 我的脚本不复制这些,它只是使用普通的curl,没有额外的标题。
导致问题的请求不会被logging。 据我所知,这不应该是这种情况,因为我告诉mod_securitylogging第一阶段,这是在Apache实际上处理请求之前的请求。
有没有人有任何其他的想法?
更新2:
strace输出的过程:
brk(0x3568c000) = 0x3568c000 brk(0x356ca000) = 0x356ca000 brk(0x35708000) = 0x35708000 brk(0x35746000) = 0x35746000 brk(0x35784000) = 0x35784000 brk(0x357c2000) = 0x357c2000 brk(0x35800000) = 0x35800000 brk(0x3583e000) = 0x3583e000 ... brk(0x3587c000) = 0x3587c000 brk(0x358ba000) = 0x358ba000 brk(0x358f8000) = 0x358f8000 brk(0x35936000) = 0x35936000 brk(0x35974000) = 0x35974000 brk(0x359b2000) = 0x359b2000 brk(0x359f0000) = 0x359f0000 brk(0x35a2e000) = 0x35a2e000 brk(0x35a6c000) = 0x35a6c000 brk(0x35aaa000) = 0x35aaa000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f2028000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f2005000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1fe2000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1fbf000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1f9c000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1f79000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1f56000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1f33000 ... mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1f10000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1eed000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1eca000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1ea7000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1e84000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1e61000 mmap(NULL, 143360, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72f1e3e000 +++ killed by SIGKILL +++
提前致谢。
我没有看到任何PHP或Java进程占用额外的资源
你认为这是值得检查的,build议你要么知道很多CGI漏洞,要么对Web服务/进程pipe理知之甚less。
最终,我想看看是什么样的请求导致这些问题
这是一个明智的开始。 最简单的解决scheme是安装mod_security并将其configuration为logging传入的请求(Apache只在发送响应的位置logging日志)。 还有其他一些方法,例如嗅探stream量(pastMon,Wireshark)或login反向代理。
有没有办法限制单个httpdsubprocess可能消耗的资源量
不是直接的,但是您应该将LimitInternalRecursion,LimitRequestBody,LimitRequestFields,LimitRequestFieldSize,LimitRequestLine,MaxKeepAliveRequests,MaxRequestsPerChild和Timeout设置为合理的值。
我可以configurationoom-daemon在httpd进程上更好地触发
把OOM Killer搞砸几乎总是一个坏主意。 即使你认为你知道你在做什么。 你是否在没有web服务器的情况下使用anythiong? 如果是这样,那么也许你应该考虑在单独的机器上运行它们。
首先,你必须限制可以启动的apache进程的最大数目。 这可以通过降低MaxSpareServers
来完成。 从低位开始(3-10),直到表演开始下降为止。 MinSpareServers
应该是2。
PHP通常作为一个Apache模块(mod_php)运行,这意味着它运行在与Apache相同的地址空间,我的意思是你会看到只有Apache进程,里面也会运行PHP。 你可以在这些进程上运行gdb
并在gdb
里面运行backtrace
,看看他们在做什么。 你也可以使用pstack
。 如果你注意到了这个URL(请查看access.log查找URL),那么你可以开始debuggingphp代码。 search一个phpdebugging器或/和一个php分析器。
终于find了答案。 结果我们托pipe的网站中有一个隐藏的.htaccess隐藏在其中的一个RewriteRule,在某些情况下触发无限循环。