Рекомендации / Хитрости по регулированию PHP-скрипта
Вопрос
У меня есть запланированная задача, которая запускает скрипт на регулярной основе (каждый час).Этот скрипт выполняет некоторое интенсивное взаимодействие с базой данных и файловой системой, и его запуск обычно занимает несколько минут.Проблема в том, что загрузка процессора сервера резко возрастает во время выполнения скрипта и замедляет нормальную работу.Есть ли способ ограничить этот процесс, чтобы он занимал больше времени, но не потреблял так много ресурсов?
Я просмотрел различные варианты конфигурации для PHP, но, похоже, нет ни одного, который соответствовал бы моим потребностям.
Установка memory_limit в php.ini на что-то меньшее приводит к тому, что мои объекты данных довольно легко переполняются.
Я видел похожие сообщения, где люди предлагали использовать sleep() в определенных точках скрипта, но это не мешает скрипту запускать сервер.
Оптимальным решением было бы каким-то образом указать стеку Lamp (в данном случае Wamp) использовать только 10% максимальной загрузки процессора.Я вообще не беспокоюсь о времени выполнения и предпочел бы, чтобы это заняло больше времени, если это означает экономию циклов процессора в секунду.Моим альтернативным решением было бы настроить другой сервер с репликацией базы данных, чтобы cron мог работать в городе, не замедляя работу всего остального.
Окружающая среда:Windows Server 2k3, Apache 2.2.11, PHP 5.2.9, MySQL 5.1
Я ценю любое понимание этой ситуации.
Редактировать: Я ценю все ответы, даже те, которые зависят от *nix.В моей ситуации еще достаточно рано менять среду хостинга.Надеюсь, этот вопрос поможет другим, независимо от операционной системы.
Решение
Это сложная проблема.Если вы запускаете PHP-скрипт через командную строку, вы можете установить низкий приоритет планирования процесса (start /low php.exe myscript.php
Я считаю).Если ваш PHP-скрипт сам выполняет большую часть обработки, потребляющей ваш процессор, это может сработать.Однако вы сказали, что выполняете тяжелое взаимодействие с базой данных и файловой системой, и это решение не поможет.Похоже, что есть подсказка MySQL «LOW_PRIORITY» для запросов INSERT и UPDATE, которая может вам в этом помочь, но я ее не пробовал.
Другие советы
Вы можете установить процессы в Windows с более низким приоритетом. Я не уверен, как этот процесс запускается, но если вы установите для процесса низкий приоритет, все, кому нужны ресурсы ЦП, получат их, если вы установите очень низкий приоритет.
В UNIX (ЛАМПА) Мне удалось решить проблему, проверив загрузку сервера перед продолжением цикла.
function get_server_load($windows = 0) {
$os = strtolower(PHP_OS);
if(strpos($os, "win") === false) {
if(file_exists("/proc/loadavg")) {
$load = file_get_contents("/proc/loadavg");
$load = explode(' ', $load);
return $load;
}
elseif(function_exists("shell_exec")) {
$load = explode(' ', `uptime`);
return $load;
}
else {
return "";
}
}
}
for(... ... ...){
$data = get_server_load();
if($data[0] < 0.2){
// continue
}else{
sleep(1);
}
}
Эта функция должна работать и в Windows, но я не могу этого гарантировать.В Linux он возвращает массив с загрузкой за последнюю минуту, 5 минут и 15 минут.
Кроме того, рассмотрите возможность запуска ваших сценариев (если через CLI) с более низким приоритетом (в Linux используйте «nice»)
Вы также можете использовать другие значения, прежде чем продолжить цикл, например, количество активных процессов Apache (вы можете проанализировать страницу 127.0.0.1/server_status?auto, если вы включили mod_status в httpd.conf), или также ситуацию MySQL (активные соединения ?)
Можете ли вы изменить запись cron, чтобы запустить скрипт, используя хороший?
Не хорошая идея использовать сервер для обслуживания клиентов и анализа данных.
Поэтому, если вы ищете окончательное решение, внесите несколько изменений в свое приложение и перенесите анализ данных из интерфейсов и действующей базы данных в другую систему, предназначенную для этой задачи.
Даже если вам удастся успешно ограничить работу анализатора, он будет использовать драгоценные ресурсы, в противном случае он будет доступен для обслуживания пользователей.
Это может оказаться трудным изменением, но, возможно, стоит провести рефакторинг структур данных в итераторы.Кроме того, если в вашем коде есть циклические ссылки, предоставьте такой метод, какclearReferences(), который сбрасывает настройки этих объектов.Кстати, эта проблема решена в PHP 5.3.
Итак, если у вас есть:
class Row
{
protected $_table;
public function __construct($table)
{
$this->_table = $table;
}
}
class Table
{
protected $_row;
public function __construct()
{
$this->_row = new Row($this);
}
}
Добавьте метод ClearReferences() в класс Row:
class Row
{
public function clearReferences()
{
$this->_table = null;
}
}
Это все, что я могу придумать на данный момент.
У меня есть несколько скриптов, которые я запускаю из cron аналогичным способом, используя nice:
0 * * * * приятно -n19 php myscript.php
Это не улучшит использование оперативной памяти (это можно сделать, только изменив способ написания сценария), но будет использоваться только тот процессор, который в противном случае простаивал бы.
РЕДАКТИРОВАТЬ:не увидел, что вопрос касается среды Windows, извините...оставив это для всех пользователей *nix, имеющих ту же проблему..
Возможно, ваш сценарий просто пытается сделать слишком много одновременно.Будет ли он работать меньше, если будет работать три раза в час?
Другим решением может быть установка дополнительного сервера только для выполнения такого рода «внутренней» обработки.Это будет особенно эффективно, если это не создает чрезмерную нагрузку на базу данных, а только на веб-сервер.
Еще один подход, на который следует обратить внимание, заключается в том, можно ли разделить работу в другом направлении.Сценарии такого типа часто содержат несколько больших операторов SQL, которые генерируют результаты, используемые для генерации множества маленьких операторов SQL.Если последние можно куда-то отложить, их можно будет запустить в базе данных на более позднем этапе.Такой подход также может позволить вам использовать небуферизованный запрос для получения данных предварительной обработки, что может значительно сократить потребление памяти кодом PHP.
Если у вас он (Apache) запущен как служба, вы можете изменить приоритет настройки в Центре управления Win / services.Загрузка вашего процессора все равно возрастет, но планировщик предпочтет другие программы .Также попробуйте установить базу данных / сервер на другом жестком диске, отличном от вашего Приложения.