FastCGI和Apache 500错误间歇

我有一个FastCGI(mod_fastcgi)问题。 它每隔一段时间就会发生一次,并不会导致完整的服务器崩溃,只有500个错误。 这里有几件事情。 首先,我使用APC,所以PHP是在控制它自己的进程,而不是FastCGI。 另外,我有webroot设置为:

/var/www/html 

而fcgi-bin里面:

 /var/www/html/fcgi-bin 

首先在这里是apache error_log:

 [Fri Jan 07 10:22:39 2011] [error] [client 50.16.222.82] (4)Interrupted system call: FastCGI: comm with server "/var/www/html/fcgi-bin/php.fcgi" aborted: select() failed, referer: http://www.domain.com/ 

我也对“fcgi-pm”stream程进行了大胆的讨论。 下面是围绕炸弹爆炸时的痕迹:

 21725 gettimeofday({1294420603, 14360}, NULL) = 0 21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6503 38*", 16384) = 46 21725 alarm(131) = 0 21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14]) 21725 alarm(0) = 131 21725 gettimeofday({1294420603, 96595}, NULL) = 0 21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6154 23*C /var/www/html/fcgi-bin/php.fcgi - - 6483 28*", 16384) = 92 21725 alarm(131) = 0 21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14]) 21725 alarm(0) = 131 21725 gettimeofday({1294420603, 270744}, NULL) = 0 21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 5741 38*", 16384) = 46 21725 alarm(131) = 0 21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14]) 21725 alarm(0) = 131 21725 gettimeofday({1294420603, 311502}, NULL) = 0 21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6064 32*", 16384) = 46 21725 alarm(131) = 0 21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14]) 21725 alarm(0) = 131 21725 gettimeofday({1294420603, 365598}, NULL) = 0 21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6179 33*C /var/www/html/fcgi-bin/php.fcgi - - 5906 59*", 16384) = 92 21725 alarm(131) = 0 21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14]) 21725 alarm(0) = 131 21725 gettimeofday({1294420603, 454405}, NULL) = 0 

我注意到,'select()'似乎保持不变,但是read()将其返回值从46更改为其他数字。 有没有人见过这样的事情? 这可能是某种文件locking?

谢谢,本

概要

我观察到了与Apache相同的行为; 看来这个问题并不是针对lighttpd的。

在我的情况下,症状是完全一样的; Apache的访问日志中充满了间歇性的500个响应代码,并且在PHP的错误日志中没有相应的条目(并且PHP错误报告被configuration为最大程度地冗长)。

我在Apache邮件列表上广泛描述了这个问题(search主题为“Access.log中的间歇500响应,没有在error.log中的对应条目”的列表存档)。

根本原因

1100110的根本原因的答案提示,但我会直接从Apache提供额外的文档,以及消除问题的build议。

下面是Apache在这个问题上的官方话语:

https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html

特殊的PHP考虑

默认情况下,PHP FastCGI在处理500个请求后处理退出,并且在这个模块已经连接到应用程序并发送下一个请求之后它们可以退出。 发生这种情况时,将会logging一个错误,并将500内部服务器错误返回给客户端。 通过将PHP_FCGI_MAX_REQUESTS设置为0,可以禁用此PHP行为,但如果PHP应用程序泄露资源,则可能会出现问题。 或者,可以将PHP_FCGI_MAX_REQUESTS设置为比默认值高得多的值,以降低此问题的频率。 可以将FcgidMaxRequestsPerProcess设置为小于或等于PHP_FCGI_MAX_REQUESTS的值来解决问题。

应始终使用mod_fcgid禁用PHPsubprocesspipe理(PHP_FCGI_CHILDREN),mod_fcgid只会一次将一个请求路由到其生成的应用程序进程; 因此,由PHP创build的任何subprocess将不会被有效使用。 (另外,PHPsubprocess可能没有正确终止。)默认情况下,如果设置PHP_FCGI_CHILDREN = 0,PHPsubprocesspipe理被禁用。

除非PHPpipe理subprocess,否则用于PHP的stream行的APC操作码caching不能在PHP FastCGI进程之间共享caching。 因此,caching的有效性受到mod_fcgid的限制; 并发的PHP请求将使用不同的操作码caching。

我们有它。

可能的解决scheme

选项1

一个解决scheme是将PHP_FCGI_MAX_REQUESTS设置为零,但采取这种措施会导致内存泄漏失控的可能性。

我所查阅的各种文档都没有说明PHP是否通过Fast-CGI遭受固有的内存泄漏(因此这种内置的“过程回收”行为),或者风险限于写得不好的“失控“脚本。

无论如何,将PHP_FCGI_MAX_REQUESTS设置为零是固有的风险,特别是在共享主机环境中。

选项2

第二个解决scheme,如上面摘录的那样,是将FcgidMaxRequestsPerProcess设置为小于或等于PHP_FCGI_MAX_REQUESTS的值。 文档忽略了一个重要的点,但是: 该值也必须大于零 (因为在这种情况下零代表“无限制”或“禁用检查”)。 假定FcgidMaxRequestsPerProcess的默认值为零,并且PHP_FCGI_MAX_REQUESTS的默认值为500,则任何未覆盖这些值的pipe理员都将遇到间歇的500响应代码。 出于这个原因,我不明白为什么FcgidMaxRequestsPerProcess和PHP_FCGI_MAX_REQUESTS不共享相同的默认值。 也许这是因为像这样configuration这两个指令产生与将PHP_FCGI_MAX_REQUESTS设置为零的相同的净结果; 文件在这方面是不明确的。

选项3

第三种解决scheme是完全放弃Fast-CGI,转而采用类似的替代方法,如suPHP或普通的CGI + SuExec。 我已经在各种PHP模式下执行了一些基本的原始性能基准testing,我的发现如下:

  1. Mod-PHP 77.7
  2. CGI 69.0
  3. suPHP 67.0
  4. Fast-CGI 55.7

Mod-PHP是performance最好的,得分为77.7。 分数是任意的,仅用于演示PHP模式下页面加载时间的相对差异。

如果我们假设这些基准是相当有代表性的,那么考虑到这个(相当严重的)实施缺陷,看起来很less有理由抱住Fast-CGI。 想到的唯一重要原因是操作码caching。 我的理解是,PHP不能通过CGI或者suPHP模式来使用操作码caching(因为进程不会跨越请求持续存在)。

虽然Fast-CGI没有充分利用op-codecaching(例如,通过APC)开箱即用,聪明的用户已经devise了一种使用Fast-CGI(通过每个用户caching)使APC有效的方法: http ://www.brandonturner.net/blog/2009/07/fastcgi_with_php_opcode_cache/ 。 但是有几个缺点:

  1. 内存(RAM)的要求相当可观,因为每个用户都有一个专用的caching。 (对于透视,考虑在Mod-PHP模式下,所有用户共享一个caching。)
  2. Apache必须使用较旧的模块mod_fastcgi,而不是较新的模块mod_fcgid。 (详情请参见上段引用的文章。)
  3. configuration相当复杂。

作为一个相关的推论,你在你的问题中说了如下:

首先,我使用APC,所以PHP是在控制它自己的进程,而不是FastCGI。

除非你使用的是mod_fastcgi(而不是mod_fcgid),并且除非你遵循了类似于上面几段所述的步骤,否则APC会消耗资源而没有效果。 因此,您可能希望禁用APC。

解决scheme摘要

采取以下三种措施之一:

  1. 将PHP_FCGI_MAX_REQUESTS环境variables设置为零。 (在PHP脚本中引入内存泄漏的可能性,使其失去控制。)
  2. 将FcgidMaxRequestsPerProcess设置为小于或等于PHP_FCGI_MAX_REQUESTS的值,但大于零。
  3. 放弃Fast-CGI有利于可比较的select,如suPHP或普通的CGI + SuExec。

我读某处(处理lighttpd,而不是apache),由于某种原因,php无法处理超过500个请求。 无论出于何种原因,第501条要求都将被炸弹。

对不起,我没有更多的信息,但至less值得一试。

tl; dr尝试将PHP_FCGI_MAX_REQUESTS设置为500,并查看问题是否自行清除。

发现这些信息,它适用于Lighttpd,我不知道它是否适用于Apache。

testing一下,如果这只是lighttpd的一个问题,或者是一个普遍问题,我很乐意听到。

为什么我的PHP应用程序不时返回错误500?

“这个问题似乎源于PHP的一个鲜为人知的问题:在处理500个请求后,PHP停止接受新的FastCGI连接;不幸的是,PHP清理代码中存在一个潜在的竞争条件,PHP可以closures,但仍然有套接字打开,所以lighty可以发送请求编号501到PHP并让它“接受”,但是PHP似乎只是退出,造成从轻微的500返回。

为了限制这种情况,请将PHP_FCGI_MAX_REQUESTS设置为500。

http://redmine.lighttpd.net/projects/1/wiki/Docs:PerformanceFastCGI

感谢您的答复。 我有所有的PHP错误去日志文件。 我收到了一些通知,但没有错误。 我必须承认,我没有写这个代码。 现在我已经使用'.htaccess'规则将所有500个错误redirect到index.php。 我必须错过一些东西。 这不应该发生。 我唯一的猜测是,一旦“PHP_FCGI_MAX_REQUESTS”达到它的最大值,php杀死了孩子,这使FastCGI混淆了。 但是,如果我理解正确PHP有一个父进程应该是唯一一个FastCGI交谈,所以我不能确定这是它…这是我的包装脚本:

 #!/bin/bash # Shell Script To Run PHP5 using mod_fastcgi under Apache 2.x # Tested under Red Hat Enterprise Linux / CentOS 5.x ### Set PATH ### PHP_CGI='/usr/bin/php-cgi -d apc.shm_size=60M' PHP_FCGI_CHILDREN=25 PHP_FCGI_MAX_REQUESTS=1000 ### no editing below ### export PHP_FCGI_CHILDREN export PHP_FCGI_MAX_REQUESTS exec $PHP_CGI 

这是非常高容量的服务器,所以这就是为什么PHP_FCGI_CHILDREN设置如此之高。

再次感谢,本