使用php fpm/Nginx下载脚本会导致CPU高负载
我有一个很好的服务器用于文件共享,下载脚本有问题。 我使用在nginx上运行的PHP-FPM 服务器规格:使用php fpm/Nginx下载脚本会导致CPU高负载,nginx,download,php,Nginx,Download,Php,我有一个很好的服务器用于文件共享,下载脚本有问题。 我使用在nginx上运行的PHP-FPM 服务器规格: 2x Intel Xeon E5 CPU: 92GB RAM 10x2TB (RAID6) And we use 1 SSD disk for CashCade 当我在apache服务器上应用这个脚本时,它工作得很好,但我想在nginx服务器上运行它,因为apache占用了大量内存。(RAM) 但是当我在nginx上运行这个脚本时,一些真正有线的事情正在发生——它需要CPU的30%,只需
2x Intel Xeon E5
CPU: 92GB RAM
10x2TB (RAID6)
And we use 1 SSD disk for CashCade
当我在apache服务器上应用这个脚本时,它工作得很好,但我想在nginx服务器上运行它,因为apache占用了大量内存。(RAM)
但是当我在nginx上运行这个脚本时,一些真正有线的事情正在发生——它需要CPU的30%,只需要一次下载!
请注意,在下载开始3-4分钟后,CPU负载将恢复正常(但下载将继续)
这是我下载LINUX时的“顶级”。。。
我不知道为什么,但是PHP-FPM脚本占用了CPU很多资源。剧本:
class ResumeDownload {
private $file;
private $name;
private $boundary;
private $delay = 0;
private $size = 0;
function __construct($file, $delay = 0) {
if (! is_file($file)) {
header("HTTP/1.1 400 Invalid Request");
die("<h3>File Not Found</h3>");
}
$this->size = filesize($file);
$this->file = fopen($file, "r");
$this->boundary = md5($file);
$this->delay = $delay;
$this->name = basename($file);
}
public function process() {
$ranges = NULL;
$t = 0;
if ($_SERVER['REQUEST_METHOD'] == 'GET' && isset($_SERVER['HTTP_RANGE']) && $range = stristr(trim($_SERVER['HTTP_RANGE']), 'bytes=')) {
$range = substr($range, 6);
$ranges = explode(',', $range);
$t = count($ranges);
}
header("Accept-Ranges: bytes");
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: binary");
header(sprintf('Content-Disposition: attachment; filename="%s"', $this->name));
if ($t > 0) {
header("HTTP/1.1 206 Partial content");
$t === 1 ? $this->pushSingle($range) : $this->pushMulti($ranges);
} else {
header("Content-Length: " . $this->size);
$this->readFile();
}
flush();
}
private function pushSingle($range) {
$start = $end = 0;
$this->getRange($range, $start, $end);
header("Content-Length: " . ($end - $start + 1));
header(sprintf("Content-Range: bytes %d-%d/%d", $start, $end, $this->size));
fseek($this->file, $start);
$this->readBuffer($end - $start + 1);
$this->readFile();
}
private function pushMulti($ranges) {
$length = $start = $end = 0;
$output = "";
$tl = "Content-type: application/octet-stream\r\n";
$formatRange = "Content-range: bytes %d-%d/%d\r\n\r\n";
foreach ( $ranges as $range ) {
$this->getRange($range, $start, $end);
$length += strlen("\r\n--$this->boundary\r\n");
$length += strlen($tl);
$length += strlen(sprintf($formatRange, $start, $end, $this->size));
$length += $end - $start + 1;
}
$length += strlen("\r\n--$this->boundary--\r\n");
header("Content-Length: $length");
header("Content-Type: multipart/x-byteranges; boundary=$this->boundary");
foreach ( $ranges as $range ) {
$this->getRange($range, $start, $end);
echo "\r\n--$this->boundary\r\n";
echo $tl;
echo sprintf($formatRange, $start, $end, $this->size);
fseek($this->file, $start);
$this->readBuffer($end - $start + 1);
}
echo "\r\n--$this->boundary--\r\n";
}
private function getRange($range, &$start, &$end) {
list($start, $end) = explode('-', $range);
$fileSize = $this->size;
if ($start == '') {
$tmp = $end;
$end = $fileSize - 1;
$start = $fileSize - $tmp;
if ($start < 0)
$start = 0;
} else {
if ($end == '' || $end > $fileSize - 1)
$end = $fileSize - 1;
}
if ($start > $end) {
header("Status: 416 Requested range not satisfiable");
header("Content-Range: */" . $fileSize);
exit();
}
return array(
$start,
$end
);
}
private function readFile() {
while ( ! feof($this->file) ) {
echo fgets($this->file);
flush();
usleep($this->delay);
}
}
private function readBuffer($bytes, $size = 1024) {
$bytesLeft = $bytes;
while ( $bytesLeft > 0 && ! feof($this->file) ) {
$bytesLeft > $size ? $bytesRead = $size : $bytesRead = $bytesLeft;
$bytesLeft -= $bytesRead;
echo fread($this->file, $bytesRead);
flush();
usleep($this->delay);
}
}
}
我不知道为什么,但是PHP-FPM脚本占用了CPU很多资源
是什么让你认为这是个问题?当服务器不受CPU限制时,程序将尽可能快地运行,使用尽可能多的可用CPU。当服务器不能足够快地处理请求时,CPU的高使用率才是真正重要的,因为所有的脚本都在竞争使用CPU资源,并且相互阻止运行
您的脚本正在以尽可能快的速度运行(即使用尽可能多的CPU),因为您已经告诉它:
$download = new ResumeDownload($file, 0); //delay about in microsecs
i、 e.您的下载脚本从未等待,因此它以尽可能快的速度循环,将数据推送到网络连接中
很明显,服务器将数据推送到网络连接的速度比通过internet发送的速度要快,因此很多时候您的脚本只是在循环并等待网络连接能够发送数据,正如“top”输出顶部的高空闲时间所证明的
您可以设置延迟使脚本真正休眠,也可以使用Nginx从PHP中完全删除负载。这里有一个配置:在您实际受到CPU限制的情况下,这将更加有效。在这种方法中增加延迟:
$download = new ResumeDownload($file, 500); //delay about in microsecs
或者使用nginx x-accel-redirect而不是ResumeDownload类我喜欢
内部
方法,以前从未想过,它阻止直接访问,并且仍然保持nginx上的负载,很好。可能重复
$download = new ResumeDownload($file, 500); //delay about in microsecs