Apache mpm-worker + mod_fcgid + php5_cgi部分和零星地向下

最近,由于内存问题,我已经从Apache mpm-prefork(PHP模块)更改为mpm-worker(PHP-FPM)。 我正在运行一个相当大的PHP应用程序,每个prefork进程需要20-30M左右。

总的来说,服务器运行稳定而且快速。 但是,有时几分钟内某些用户不能使用该页面。

工作假设1(=粗略的想法)是其中一个进程(通常为2,有时达到5或6)挂起,每个分配给该进程的客户端(例如50%的客户端)收到错误消息。

工作假设2是MaxRequestsPerProcess负责。 在500次调用之后,进程试图closures,mod_fcgid没有正常地杀死,而当进程正在等待kill时,进一步的客户被分配给(并被拒绝)进程。 但是我不能真正想象Apache会如此愚蠢。

我的问题是:除了一些错误日志没有什么

[warn] mod_fcgid: process ???? graceful kill fail, sending SIGKILL 

我正在想什么来追踪这个问题。 它似乎是零星的,我还没有设法挑起它。 服务器性能(CPU / RAM)不会成为问题,因为最近几周总体负载已经在较低的范围内。

感谢任何提示。 对我的假设的任何意见(这并没有帮助我find解决scheme,但 – 我试图禁用MaxRequestsPerProcess,但不知道是否有帮助)? 我将非常感谢一些想法如何跟踪这个问题。

Apacheconfiguration

  <Directory /var/www/html> ... # PHP FCGI <FilesMatch \.php$> SetHandler fcgid-script </FilesMatch> Options +ExecCGI </Directory> <IfModule mod_fcgid.c> FcgidWrapper /var/www/php-fcgi-starter .php # Allow request up to 33 MB FcgidMaxRequestLen 34603008 FcgidIOTimeout 300 FcgidBusyTimeout 3600 # Set 1200 (>1000) for PHP_FCGI_MAX_REQUESTS to avoid problems FcgidMaxRequestsPerProcess 1000 </IfModule> 

Apache模块configuration

 <IfModule mod_fcgid.c> AddHandler fcgid-script .fcgi FcgidConnectTimeout 20 FcgidBusyTimeout 7200 DefaultMinClassProcessCount 0 IdleTimeout 600 IdleScanInterval 60 MaxProcessCount 20 MaxRequestsPerProcess 500 PHP_Fix_Pathinfo_Enable 1 </IfModule> 

注意:超时设置为2小时,因为很less,应用程序可能需要一些时间来运行(例如每晚做一个数据库优化的cronjob)。

起始脚本

 #!/bin/sh PHP_FCGI_MAX_REQUESTS=1200 export PHP_FCGI_MAX_REQUESTS export PHPRC="/etc/php5/cgi" exec /usr/bin/php5-cgi #PHP_FCGI_CHILDREN=10 #export PHP_FCGI_CHILDREN 

软件包版本

  • 系统:Ubuntu 12.04.2 LTS
  • apache2-mpm-worker:2.2.22-1ubuntu1.4
  • libapache2-mod-fcgid:1:2.3.6-1.1
  • php5-common:5.3.10-1ubuntu3.7

我认为每个进程20-30MB是相当小的。 这完全是相对的,但是例如大多数CMS应用程序将需要至less100MB。 如果有问题的话,您的最大上传大小也会受到最大进程大小的限制。

当你的服务器不可用时,php工作进程可能很忙,但这只是一个近因。 有些东西是放缓你的服务器,至less有一段时间,PHP进程无法跟上传入的请求。 什么是减慢你的服务器很难判断,但“优美的杀死失败”让我觉得被杀死的进程可能在磁盘上等待。

你在这种情况下login了吗? 系统是否感觉到响应?

最后,看看进程状态,并查找正在等待IO的'D'。 有很多吗? 总结上面的'wa'是过程花费在IO上等待的总时间。 (它说百分比,但这可能是一个处理器时间的百分比)。 像iotop,atop和vmstat这样的工具对于获取磁盘绑定的进程以及磁盘限制整体性能的程度也很有用。

您了解工作进程无法接受新请求时发生的情况不正确。 新请求将不会被分配给它。

杀死工人之前的1000个请求是很高的。 我build议把它放到10到50之间。

我认为你在Hypopthesis 1的正确轨道。mc0e的build议是相当稳固的,所以我主要增加它。

那些你看到的日志消息表明,单独的进程在prefork MPM下被locking,这比你的工作者提供了更好的进程隔离。 我以前在生产环境中看到过这个,这意味着你有一些行为不当的代码。

在你的每个孩子的高请求和你的挂起的进程之间,这为内存膨胀设置了一个阶段。 该文档特别包含了一个事实,即非零值有助于防止内存泄漏 ,但是如果将该值设置得过高,则其优点将丢失。 把你的进程挂在上面,进一步增加了整个内存的占用空间。

这给你两个即时的外卖:

  • 降低MaxRequestsPerChild的大幅度,正如mc0e所暗示的那样。 这有助于防止个人进程活得足够长,以积累大量的内存泄露……但正如他所说,20-30M可能不是什么大不了的事情。
  • find你的错误。 您正在寻找内存泄漏和执行死锁(mc0ebuild议的资源争用,但也要看看当networking资源变得无法访问或无响应时,您的代码执行的操作)。 在你的大进程上运行lsof 可能会提供一个暗示,这取决于代码在做什么(例如,文件句柄泄漏,以及触发最大文件句柄限制可能与进程死锁有关),但除此之外,你正在寻找代码debugging。