Проблемы с импортом больших XML-каналов (LAMP) - PullRequest
0 голосов
/ 28 октября 2009

Интересно, кто-нибудь может мне помочь с небольшой проблемой cron?

Проблема в том, что нагрузка может возрасти до 5, а загрузка процессора может подскочить до 40%, на двухъядерном«Xeon L5410 @ 2,33 ГГц» с оперативной памятью 356 МБ, и я не уверен, где мне следует вносить изменения в код и как это предотвратить.Пример кода ниже

// Примечание. $ productFile может быть сжатым 40 МБ .gz, несжатым 700 МБ (текстовый файл xml) if (file_exists ($ productFile)) {

  $fResponse = gzopen($productFile, "r");
  if ($fResponse) {

     while (!gzeof($fResponse)) {

        $sResponse = "";
        $chunkSize = 10000;
        while (!gzeof($fResponse) && (strlen($sResponse) < $chunkSize)) {
          $sResponse .= gzgets($fResponse, 4096);
        }
        $new_page .= $sResponse;
        $sResponse = "";
        $thisOffset = 0;
        unset($matches);

        if (strlen($new_page) > 0) {

           //Emptying
           if (!(strstr($new_page, "<product "))) {
              $new_page = "";
           }

           while (preg_match("/<product [^>]*>.*<\/product>/Uis", $new_page, $matches, PREG_OFFSET_CAPTURE, $thisOffset)) {

              $thisOffset = $matches[0][1];
              $thisLength = strlen($matches[0][0]);
              $thisOffset = $thisOffset + $thisLength;

              $new_page   = substr($new_page, $thisOffset-1);
              $thisOffset = 0;

              $new_page_match = $matches[0][0];

              //- Save collected data here -//

              }

           }//End while loop


        }

     }
     gzclose($fResponse);
  }

}

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

С 40000 соответствуетшипы нагрузки / процессора.Так что у кого-нибудь есть советы о том, как управлять большими загрузками через cron.

Заранее благодарим за помощь

Ответы [ 4 ]

1 голос
/ 28 октября 2009

У вас есть как минимум две проблемы. Во-первых, вы пытаетесь распаковать весь 700 МБ файл в память. На самом деле, вы делаете это дважды.

while (!gzeof($fResponse) && (strlen($sResponse) < $chunkSize)) {
    $sResponse .= gzgets($fResponse, 4096);
}
$new_page .= $sResponse;

И $sResponse, и $new_page будут содержать строку, которая будет содержать весь файл размером 700 МБ. Таким образом, к моменту завершения работы скрипта вы получаете 1,4 ГБ памяти, не говоря уже о стоимости конкатенации строк (хотя PHP обрабатывает строки лучше, чем в других языках, существуют ограничения на то, что получит изменяемый и не изменяемый вы)

Вторая проблема заключается в том, что вы запускаете регулярное выражение для все более крупной строки в $new_page. Это увеличит нагрузку на сервер, так как $new_page становится все больше и больше.

Самый простой способ решить ваши проблемы - это разделить задачи.

  1. Перед любой обработкой распакуйте весь файл на диск.

  2. Используйте синтаксический анализатор XML на основе steram , например XMLReader или старый SAX анализатор на основе событий .

  3. Даже с парсером, основанным на потоке / событии, сохранение результатов в памяти может в конечном итоге съесть много оперативной памяти. В этом случае вы захотите взять каждое совпадение и сохранить его на диске / в базе данных.

0 голосов
/ 28 октября 2009

Ре Алан. Скрипт никогда не будет хранить 700 МБ в памяти, так как похоже, что $sResponse очищается сразу после того, как он достигнет $ chunkSize и был добавлен в $ new_page,

$new_page .= $sResponse;
$sResponse = "";

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

$new_page   = substr($new_page, $thisOffset-1);

if (!(strstr($new_page, "<product "))) {
   $new_page = "";
}

Хотя я не могу сказать, что вижу, в чем проблема.

0 голосов
/ 28 октября 2009

Вы также можете взглянуть на синтаксический анализатор XML на основе событий SAX в PHP - http://uk3.php.net/manual/en/book.xml.php

Это хорошо для анализа больших XML-файлов (мы используем его для XML-файлов того же размера, с которым вы работаете), и это делает довольно хорошую работу. Тогда не нужно регулярных выражений:)

Вам нужно сначала распаковать файл перед его обработкой.

0 голосов
/ 28 октября 2009

Поскольку вы сказали, что используете лампу, могу я предложить ответ на один из моих вопросов: Предложения / хитрости по регулированию PHP-скрипта

Он предлагает использовать команду nice в скрипте-нарушителе, чтобы снизить вероятность его сбоя на сервере.

Альтернативой может быть профилирование сценария и просмотр наличия узких мест. Я бы порекомендовал xdebug и kcachegrind или webcachegrind. Существует множество вопросов и веб-сайтов, которые помогут вам настроить профилирование сценариев.

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