Предложения / хитрости для регулирования PHP-скрипта - PullRequest
7 голосов
/ 15 апреля 2009

У меня есть запланированное задание, которое запускает скрипт на регулярной основе (каждый час). Этот скрипт интенсивно взаимодействует с базой данных и файловой системой, и его запуск занимает несколько минут. Проблема заключается в том, что во время работы скрипта увеличивается загрузка ЦП на сервере, что замедляет обычные операции. Есть ли способ ограничить этот процесс, чтобы он занимал больше времени, но не потреблял столько ресурсов?

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

Ответы [ 9 ]

8 голосов
/ 15 апреля 2009

Это сложная проблема. Если вы запускаете скрипт PHP через командную строку, вы можете установить низкий приоритет планирования процесса (start /low php.exe myscript.php, я полагаю). Если ваш PHP-скрипт сам выполняет большую часть обработки, потребляющей ваш процессор, это может сработать. Тем не менее, вы сказали, что выполняете тяжелое взаимодействие с базой данных и файловой системой, но это решение не поможет. Похоже, что в MySQL есть подсказка «LOW_PRIORITY» для запросов INSERT и UPDATE, которая может вам помочь, но я не пробовал их.

3 голосов
/ 16 апреля 2009

В UNIX (LAMP) Мне удалось решить проблему, проверив загрузку сервера перед продолжением цикла

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 это возвращает массив с загрузкой за последние 1 минуту, 5 минут и 15 минут

Также рассмотрите возможность запуска ваших скриптов (если CLI) с более низким приоритетом (в Linux используйте «nice»)

Вы также можете использовать другие значения перед продолжением цикла, например, количество активных процессов Apache (вы можете проанализировать страницу 127.0.0.1/server_status?auto, если вы включили mod_status в httpd.conf), или также ситуацию MySQL (активные соединения?)

3 голосов
/ 15 апреля 2009

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

2 голосов
/ 15 апреля 2009

Не очень хорошая идея использовать сервер для обслуживания клиентов и анализа данных.

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

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

2 голосов
/ 15 апреля 2009

Можете ли вы изменить запись cron для запуска скрипта, используя nice ?

1 голос
/ 17 апреля 2009

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

Другим решением может быть установка дополнительного сервера только для выполнения такого рода «внутренней» обработки. Это было бы особенно эффективно, если бы оно не создавало чрезмерную нагрузку на базу данных, а только на веб-сервер.

Еще один подход к рассмотрению - можно ли разделить его работу в другом направлении. Эти виды сценариев часто имеют несколько больших операторов SQL, которые генерируют результаты, используемые для генерации большого количества маленьких операторов SQL. Если последние могут быть где-то отложены, они могут быть запущены для базы данных в качестве более позднего шага. Такой подход может также позволить вам использовать небуферизованный запрос для извлечения данных предварительной обработки, что может значительно сократить потребление памяти кодом PHP.

1 голос
/ 15 апреля 2009

У меня есть куча скриптов, которые я запускаю из cron аналогичным образом, используя nice:

0 * * * * nice -n19 php myscript.php

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

РЕДАКТИРОВАТЬ: не видел, что вопрос касался среды Windows, извините ... оставил это для любых * nix пользователей, имеющих такую ​​же проблему

1 голос
/ 15 апреля 2009

Это может быть трудное изменение, но оно может стоить рефакторинга ваших структур данных в итераторы. Кроме того, если в вашем коде есть циклические ссылки, предоставьте метод, подобный 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;
    }
}

Это все, что я могу придумать на данный момент.

0 голосов
/ 15 апреля 2009

Если у вас он (Apache) работает как служба, вы можете изменить приоритет настройки в Win control center / services. Ваше использование ЦП в любом случае резко возрастет, но другие программы будут предпочтительнее по планировщику. Также попробуйте поставить базу данных / сервер на другой жесткий диск, чем ваш Приложения.

...