我有一个与Apache服务器和PHP应用程序相关的大问题。
该服务器正在提供一个相当高流量的网站,该网站正在使用PHP运行。
每24个或48个小时,Apache都会挂起,我必须重新启动它才能再次访问该网站。我必须重新启动它,因为Apache达到了允许的进程/服务器的最大数量(对我来说是16000),而它无法释放其他进程,因为其他进程都是活动状态。
托管在此服务器上的网站是一个PHP应用程序,它在最后提供文件:假设它是一个下载服务器。
浏览器通过提交POST请求的表单请求文件。
问题在于,这个POST请求似乎永远不会结束(我可以看到我的服务器状态中几乎所有的16000个进程都是POST请求)。
要服务的文件很大(10M到2G),我使用PHP readfile函数来服务它们(我不想使用href链接来服务它们,所以我使用一个form POST请求,这样用户就看不到文件在我的文件系统中的位置)。
即使我在其结尾处使用exit(),使用PHP readfile的函数似乎永远不会结束(请参见下面的代码片段)。
我在这里寻求一种避免这些由我的PHP代码引起的永远不会结束的POST请求的方法。我希望保留POST文件服务方式。
首先是我的配置:
- Ubuntu服务器14.04
- Apache 2.4与MPM prefork
- PHP 5.5.9 (mod PHP)
- 硬件:128G RAM
我的mpm_prefork.conf文件:
<IfModule mpm_prefork_module>
StartServers 512
MinSpareServers 512
MaxSpareServers 1024
ServerLimit 16000 # no problem with my server ram
MaxRequestWorkers 16000
MaxConnectionsPerChild 10000
</IfModule>
我的 apache2.conf 文件:
...
Timeout 300
KeepAlive On
MaxKeepAliveRequests 500
KeepAliveTimeout 5
...
我的php.ini文件:
max_execution_time = 7200
我的Apache日志文件:对于我的问题没有任何有趣的内容。
还有我的服务器类(导致问题的代码):
class Server
{
/* the file is served from a remote url source */
public function serveFileFromUrl()
{
if (empty($_POST)) {
return;
}
$url = $_POST['file_url'];
$mime = $_POST['mime'];
$name = sanitizeFileName($_POST['name']) . uniqid() . '.' . $mime;
$size = $_POST['size'];
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
// for Internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
} else {
// not for internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header("Content-Transfer-Encoding: Binary");
header('Pragma: no-cache');
}
ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile)
flush(); // fix memory problems with readfile
readfile($url);
@ob_end_flush();
exit();
}
/* file is served from my filesystem */
public function serveFileFromPath()
{
if (empty($_POST)) {
return;
}
$url = APP_PATH . '/download/' . $_POST['file_name'];
$mime = $_POST['mime'];
$name = sanitizeFileName($_POST['name']) . '-' . uniqid() . '.' . $mime;
$size = $_POST['size'];
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
// for Internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
} else {
// not for internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header("Content-Transfer-Encoding: Binary");
header('Pragma: no-cache');
}
ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile)
flush(); // fix memory problems with readfile
readfile($url);
@ob_end_flush();
exit();
}
}
是否有解决方法可以避免无休止的POST请求?如果能解决这个问题,我可以通过其他方式来提供文件。
请不要重复,我已经添加了足够的代码、配置片段和图片以使这个问题更具体 :)
error_reporting(-1);
。调用您的Server类的是什么,我们确定它是否到达那里,而不是在那之前挂起? - Drazisil