PHP readfile() никогда не заканчивается и заставляет сервер Apache зависать

У меня большая проблема с сервером Apache, приложением php.

Сервер обслуживает сайт с довольно высоким трафиком, который работает с php.

Каждые 24 часа или 48 часов зависает apache, и мне приходится перезагружать его, чтобы снова получить доступ к веб-сайту. Я должен перезагрузить его, потому что apache достигает максимального количества разрешенных процессов / серверов (16000 для меня), и он не может освободить другие процессы, потому что все другие процессы активны.

Веб-сайт, размещенный на этом сервере, является приложением php, которое в конце концов обслуживает файл: допустим, это сервер загрузки.

Файлы запрашиваются браузером через форму, которая отправляет запрос POST.

Проблема в том, что этот почтовый запрос никогда не заканчивается (я вижу, что почти все 16000 процессов на моем сервере являются запросами POST).

Файлы, которые обслуживаются, являются большими файлами (от 10M до 2G), и я передаю их с помощью функции php readfile (я не хочу предоставлять им ссылку href, поэтому я использую запрос POST формы, чтобы пользователь никогда не видел, где находится файл находится в моей файловой системе).

Функция, которая использует php readfile, кажется, никогда не завершится, даже если я использую exit() в конце (см. Фрагмент кода ниже).

Я прошу здесь, чтобы избежать этого бесконечного POST-запроса, вызванного моим php-кодом. Я хочу сохранить POST способ подачи файлов.

Сначала мой конф:

  • Ubuntu сервер 14.04
  • Apache 2.4 с MPM Prefork
  • php 5.5.9 (мод 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: ничего интересного для моей проблемы

Мунинский график, показывающий, когда возникает проблема:

Состояние моего сервера 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-запросов? Я в порядке, чтобы обслуживать файлы с помощью чего-то другого, чем PHP, если это может решить проблему.

Пожалуйста, не дублируйте, я добавил достаточно кода, фрагмент кода и картинки, чтобы конкретизировать этот вопрос:)

1 ответ

Решение

mod_xsendfile - хорошая альтернатива доставке файлов на PHP.

https://tn123.org/mod_xsendfile/

В противном случае вы можете просто добавить ограничение времени к вашему PHP-скрипту, чтобы он не мог работать вечно.

http://php.net/manual/de/function.set-time-limit.php

Другие вопросы по тегам