PHP-FPM/FastCGI+exit()导致CPU峰值


PHP-FPM / FastCGI + exit() causing CPU spikes

我在切罗基1.2.101上的FastCGI中运行Archlinux/php-fpm 5.3.9的一些服务器上遇到了间歇性问题。我正在使用一个缓存插件,它使用以下逻辑构建并提供静态缓存文件:

$cache_file = md5($host . $uri) . '.cache';
if( file_exists($cache_file) ) {
  $cache_file_contents = file_get_contents($cache_file)
  exit( $cache_file_contents );
}
// else build/save the $cache_file

一些进程最终会出现在挂在exit()调用上的php-fpm的慢速日志中。当负载达到峰值时,100%的CPU使用率(几乎)完全转移到Web服务器,PHP页面开始返回500-内部服务器错误。有时服务器自己恢复,其他的我需要重新启动php-fpm和cherokee。

  • 我已将PHP-FPM的FastCGI设置配置为执行

  • 即使这是一个VPS,我也会暂时排除文件系统上的IO等待,因为缓存文件应该已经加载了。我还没能在用vmstat 测试的过程中捕捉到它

  • 我将pm.max_requests设置为500,但不知道exit()调用是否会干扰进程的循环。

  • php-fpm日志显示了很多WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers)。这似乎是php-fpm通过调节池中子进程数量的正常部分

任何有关故障排除的提示都将不胜感激。以下是我发现的引起一些危险信号的3件事:

http://www.php.net/manual/en/function.exit.php#96930

https://serverfault.com/questions/84962/php-via-fastcgi-terminated-by-calling-exit#85008

为fastCGI调用exit()函数时出错?

这可能与将输出传递到服务器(也跟踪I/O)有关。您可以通过让您的Web服务器为静态缓存文件提供服务来避免FPM。除此之外,我建议您使用这个PHP块来减少一点内存/I/O:

if (file_exists($cache_file))
{
    readfile($cache_file)
    exit;
}

参见readfile

如果你不想使用exit(我个人从未遇到过在PHP中使用FastCGI的问题),你应该清理你的代码,这样就没有必要使用exit,例如你可以使用return或查看你的代码流,为什么你需要使用exit并消除问题。

我最终使用了Pythonic Exception包装方法,该方法在http://www.php.net/manual/en/function.exit.php

在主索引.php中

class SystemExit extends Exception {}
try{ 
    /* Resume loading web-app */
}
catch (SystemExit $e) {}

在问题的缓存逻辑中,替换exit( $cache_file_contents );

while (@ob_end_flush());
flush();
echo $cache_file_contents;
throw new SystemExit();

这缓解了显示挂在exit()上的php-fpm慢速日志。我不完全相信它解决了根本问题,但它已经清理了日志文件。