Достигаете оптимального размера «фреда»? - PullRequest
2 голосов
/ 18 мая 2011

Хорошо, я знаю, что мой вопрос не совсем конкретный, так как оптимальный размер фрагмента фреда - это скорее пробная ошибка.Тем не менее, я надеялся, что некоторые из вас, ребята, могли бы пролить некоторый свет на это.

Это также связано с серверными вещами, поэтому я не уверен, что Stackoverflow - это совершенно правильное место, но, похоже, это был лучший выбор.по сравнению с ServerFault.

Для начала я опубликую два снимка экрана:

http://screensnapr.com/e/pnF1ik.png

http://screensnapr.com/e/z85FWG.png

Теперь яУ меня есть скрипт, который использует PHP для потоковой передачи файлов конечному пользователю.Он использует fopen и fread для потоковой передачи файла.Большинство из этих файлов имеют размер более 100 МБ.Меня беспокоит то, что иногда вышеизложенное превращает мою статистику в серверДва экрана с разных серверов;оба сервера имеют выделенные блоки потоковой передачи файлов.Ничто иное не работает на них, кроме потоковой передачи файла PHP конечному пользователю.

Я запутался в том факте, что даже когда мой сервер передает конечному клиенту всего лишь около 4 МБ / с данных в целом(s), чтение диска идет со скоростью 100M / s и более.Этот безумный уровень ввода-вывода в конечном итоге блокирует мой процессор, потому что он ожидает ввода-вывода и задачи накапливаются;в конце концов мой сервер перестает отвечать на запросы и требует перезагрузки.

Мой текущий размер фрагмента фреда установлен на 8 *1024* 1018 *.Мой вопрос, поможет ли изменение размера блока и экспериментов?Клиент загружает данные только со средней скоростью ~ 4 МБ / с.Так почему же данные с диска читаются со скоростью 100 МБ / с?Я перепробовал все возможные решения на стороне сервера;Я даже поменял диски на новые, чтобы исключить потенциальную проблему с диском.Похоже, это проблема сценария;Может быть, PHP читает все данные с диска независимо от того, сколько они передают конечному клиенту?

Любая помощь будет приветствоваться.И если это относится к ServerFault, то мои извинения за размещение здесь.И если вам, ребята, понадобится, чтобы я опубликовал фрагменты реального сценария, я тоже могу это сделать.

Ответы [ 3 ]

3 голосов
/ 18 мая 2011

8 *1024* 1001 * байтов ?Это кажется вполне разумным, и в этом случае ваш высокий дисковый ввод-вывод, вероятно, связан с одновременным запросом.Рассматривали ли вы реализацию какого-либо регулирования полосы пропускания?Вот реализация только для PHP, которую я сделал для своей платформы: phunction :

public static function Download($path, $speed = null, $multipart = false)
{
    if (strncmp('cli', PHP_SAPI, 3) !== 0)
    {
        if (is_file($path) === true)
        {
            while (ob_get_level() > 0)
            {
                ob_end_clean();
            }

            $file = @fopen($path, 'rb');
            $size = sprintf('%u', filesize($path));
            $speed = (empty($speed) === true) ? 1024 : floatval($speed);

            if (is_resource($file) === true)
            {
                set_time_limit(0);
                session_write_close();

                if ($multipart === true)
                {
                    $range = array(0, $size - 1);

                    if (array_key_exists('HTTP_RANGE', $_SERVER) === true)
                    {
                        $range = array_map('intval', explode('-', preg_replace('~.*=([^,]*).*~', '$1', $_SERVER['HTTP_RANGE'])));

                        if (empty($range[1]) === true)
                        {
                            $range[1] = $size - 1;
                        }

                        foreach ($range as $key => $value)
                        {
                            $range[$key] = max(0, min($value, $size - 1));
                        }

                        if (($range[0] > 0) || ($range[1] < ($size - 1)))
                        {
                            ph()->HTTP->Code(206, 'Partial Content');
                        }
                    }

                    header('Accept-Ranges: bytes');
                    header('Content-Range: bytes ' . sprintf('%u-%u/%u', $range[0], $range[1], $size));
                }

                else
                {
                    $range = array(0, $size - 1);
                }

                header('Pragma: public');
                header('Cache-Control: public, no-cache');
                header('Content-Type: application/octet-stream');
                header('Content-Length: ' . sprintf('%u', $range[1] - $range[0] + 1));
                header('Content-Disposition: attachment; filename="' . basename($path) . '"');
                header('Content-Transfer-Encoding: binary');

                if ($range[0] > 0)
                {
                    fseek($file, $range[0]);
                }

                while ((feof($file) !== true) && (connection_status() === CONNECTION_NORMAL))
                {
                    ph()->HTTP->Flush(fread($file, round($speed * 1024)));
                    ph()->HTTP->Sleep(1);
                }

                fclose($file);
            }

            exit();
        }

        else
        {
            ph()->HTTP->Code(404, 'Not Found');
        }
    }

    return false;
}

Приведенный выше метод имеет некоторые незначительные зависимости и добавляет некоторые ненужные функции, такие как загрузка из нескольких частей, ноу вас должна быть возможность повторно использовать логику регулирования без проблем.

// serve file at 4 MBps (max)
Download('/path/to/file.ext', 4 * 1024);

Вы можете даже быть более щедрым по умолчанию и уменьшить значение $speed в зависимости от значений, которые вы получите из первого индекса sys_getloadavg(), чтобы избежать нагрузки на ваш процессор.

0 голосов
/ 18 мая 2011

Теперь у меня есть скрипт, который использует PHP для потоковой передачи файлов конечному пользователю.

Просто чтобы прояснить, что на самом деле происходит, Apache отвечает за фактический «поток»,PHP напрямую работает с Apache для его вывода.Поэтому ваш конечный пользователь для сценария PHP - Apache.Затем Apache обрабатывает вывод для пользователя, который, по-видимому, в вашем случае составляет около ~ 4 МБ / с.Apache, однако, не имеет такого ограничения и может принять все ваши выходные данные сразу, а затем обработать отложенную доставку клиенту.Чтобы доказать это, вы должны увидеть выход своего скрипта до доставки потока.Если ваш сценарий оборачивается и пытается доставить другой файл, то вы ставите Apache в очередь на ресурсы вашего сервера.

Лучшим решением может быть позволить Apache полностью обработать доставку файла, позволяя пользователю запрашивать загрузку издоступный URL.Очевидно, это ограничено статическим контентом.Чтобы исправить вышеприведенный сценарий, потребуется отложить чтение некоторых файлов, чтобы Apache мог доставить блоки, а не буферизовать весь вывод.

РЕДАКТИРОВАТЬ: если с вашей памятью все в порядке и мы можем исключить активность подкачки,тогда это могут быть просто параллельные запросы на чтение файла.Если мы запрашиваем 5 файлов по 100 МБ, то это 500 МБ активности чтения.Apache не будет ограничивать ваш скрипт и фактически буферизует весь вывод, который может быть более 100 Мб за раз.Это будет учитывать большую активность дискового ввода-вывода, потому что каждый запрос приводит к чтению полного файла в буфер.Использование дросселя в соответствии с предложением Alix позволит выполнять больше параллельных запросов, но в конечном итоге вы достигнете предела.Мы не можем быть уверены, насколько быстро пользователь получает данные от Apache, поэтому вам, возможно, придется найти хороший баланс для размера газа, чтобы Apache и PHP могли работать с кусками ваших файлов вместо всего файла.

0 голосов
/ 18 мая 2011

Как правило, может случиться так, что фактический ввод-вывод будет быстрее, чем ввод-вывод пользовательского пространства из-за предварительной выборки и издержек файловой системы. Однако это никогда не должно блокировать ваш сервер. Размер кеша практически не повлияет на это, если он находится между 1 КБ и, скажем, 16 МБ. Однако вместо того, чтобы использовать php для потоковой передачи файлов, вы должны рассмотреть гораздо более оптимизированный readfile .

При этом, за исключением серьезной ошибки программирования, это поведение, вероятно, не имеет прямого отношения к вашему маленькому циклу. Во-первых, вы должны использовать iotop, чтобы узнать, какая программа на самом деле вызывает ввод / вывод. Если это php (сколько одновременных скриптов? Извините, скриншоты кажутся полностью искаженными и не содержат никакой полезной информации), исключите использование буферизации вывода и посмотрите на потребление памяти, а также различные параметры настройки php (phpinfo имеет хороший обзор). Кстати, htop - лучшая альтернатива top;).

...