Проблемы с производительностью и памятью в PHP fwrite () - PullRequest
2 голосов
/ 01 мая 2019

Редактировать : Первоначально я думал, что эта проблема связана с PHP-FPM, потому что мой хост подразумевал это (см. Ниже).Я нашел способ настроить мой тестовый сервер на использование PHP-FPM (cgi-fcgi), и скрипт работал без проблем с производительностью и памятью.Возможно, на сервере моего хоста есть что-то еще, что делает странные вещи, такие как отслеживание записей в файлах и запись записанного содержимого в память без причины.Кто-нибудь знает, есть ли такое программное обеспечение / модули, которые могли бы сделать это?Тем временем я снова свяжусь с моим хостом ...

Проблема

У меня есть PHP-скрипт, который записывает данные в файл, используя fwrite().На моем виртуальном хостинге, на котором работает сервер CloudLinux, производительность снижается, а память исчерпывается, когда требуется много данных.Кажется, проблема в PHP-FPM, который Apache использует на сервере.Если я подключаюсь к серверу по SSH и запускаю тот же сценарий с PHP-CLI, производительность становится намного лучше (до 7 раз быстрее), а использование памяти остается более или менее одинаковым на протяжении всего сценария.

Iнаписал простой тестовый скрипт, чтобы проиллюстрировать это:

echo 'SAPI: ' . php_sapi_name(); // Shows if you're using fcgi or cli
if (php_sapi_name() === 'cli') { // Set appropriate line break char
    $eol = PHP_EOL;
}
else {
    $eol = '<br>';
}
echo $eol;
echo 'Starting fwrite...' . $eol;

$time_start = microtime(true); 
$fh = fopen('/some/path/test-fw.txt', 'w');
$i = 0;
while ($i < 2000000) {
    $str = 'row-' . $i . ': this is a test string abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg ';
    fwrite($fh, $str);
    $i++;
}
echo 'fwrite done!' . $eol;
echo 'Time taken: ' . (microtime(true) - $time_start) . 's' . $eol;
fclose($fh);
echo 'Sleeping for 60s before exiting...';
sleep(60); // Give you some time to check memory usage (in CPanel)

Результаты теста:

  • При вызове из браузера использование памяти начинается с 30 МБ и к концу возрастает до ~ 330 МБ.сценария.Время выполнения составляет около 78 секунд.
  • При вызове с помощью PHP-CLI использование памяти остается на уровне около 30 МБ.Время выполнения составляет около 10 секунд.

Использование памяти - это использование физической памяти, показанное на CPanel.Кстати, размер файла составляет около 300 МБ, поэтому я подумал, если бы содержимое, написанное с помощью fwrite (), также было помещено в память PHP-FPM!

Я надеялся обойти эту проблему, выполнив exec('php-cli script.php')в другом сценарии, но это не сработало.Все, что он сделал, это создал php-cli процесс как потомок процесса php-cgi.

Служба поддержки моего хоста сказала мне, что "CGI помещает все в память, если вы не скажетеэто "сбросить" его, и CGI разработан, чтобы быть менее интенсивным процессором ".Я был несколько озадачен, потому что я не мог видеть, что там можно «сбросить» в моем коде, чтобы освободить память.Я имею в виду, что в моем тестовом скрипте CGI хранит каждый $str, переданный fwrite(), если я не запрещаю это явно?Если да, то как мне это сделать (пробовал unset(), что не помогло)?

К сожалению, я не смог изменить обработчик PHP на виртуальном хостинге.В противном случае, я бы просто использовал mod_php, который я сейчас использую на своем локальном тестовом сервере, без заявленных проблем.

Интересно, есть ли у кого-нибудь подобный опыт, который мог бы указать мне правильное направление.Если это имеет какое-либо значение, я использую план питания Inmotion Hosting, в котором для моей учетной записи выделено 2 ГБ физической памяти.

Чтобы уточнить: память, похоже, откатилась назадк норме вскоре после вызова fclose() и начала периода сна.Так что я думаю, что fwrite() вызывает эту странную проблему.fflush() и set_file_buffer($fh, 0) не помогли.Как будто контент записывается на диск, но в то же время сохраняется в памяти, и я не знаю, что является причиной последнего ...

...