Отладка длительной работы PHP скрипт

У меня php script работает как задание cron, широко используя сторонний код. script сам имеет несколько тысяч LOC. В основном это импорт/обработка данных script. (JSON для MySQL, но он также делает много HTTP-вызовов и некоторых SOAP).

Теперь производительность понижается со временем. При тестировании с несколькими записями (около 100) производительность работает нормально, это делается через 10-20 минут. При запуске цельного импорта (около 1600 записей) среднее время импорта одной записи постоянно растет, а целая вещь занимает более 24 часов, поэтому по крайней мере в 5 раз дольше, чем ожидалось.

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

Итак, мне нужно отладить его, чтобы найти узкое место. Это может быть проблема с script, базовой базой кода, самой php, базой данных, os или сетевой частью. На данный момент я подозреваю какое-то кэширование где-то, что плохо ведет себя с почти 100% -ным отсутствием отношения.

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

Итак, вопрос: как я могу отладить этот вид script?

Версия PHP: 5.4.41 ОС: Debian 7.8 При необходимости я могу иметь привилегии root и устанавливать инструменты. Но это производственный сервер и, в идеале, отладка не должна слишком прерываться.

Ответы

Ответ 1

Инструмент профилирования:

Существует инструмент профилирования PHP, называемый Blackfire, который в настоящее время находится в открытой бета-версии. Существует специальная документация о том, как профилировать приложения CLI. После того, как вы собрали профиль, вы можете проанализировать поток управления приложениями с помощью измерений времени в хорошем пользовательском интерфейсе: Инструмент Blackfire

Потребление памяти подозрительное:

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

Рост использования памяти на самом деле звучит подозрительно! Если текущий набор данных не зависит от всех предыдущих наборов данных импорта, то растущая память, скорее всего, означает, что все импортированные наборы данных хранятся в памяти, что плохо. PHP также может часто пытаться собрать мусор, просто чтобы узнать, что извлечь из памяти нечего. Особенно длительные задачи CLI затронуты, поэтому обязательно прочтите сообщение в блоге, в котором обнаружено поведение.

Ответ 2

Да, его возможно, и вы можете использовать Kint (отладка PHP Script)

Что это? Kint for PHP - это инструмент, предназначенный для представления ваших данных отладки самым лучшим образом.

Другими словами, это var_dump() и debug_backtrace() на стероидах. Простой в использовании, но мощный и настраиваемый. Важное дополнение к вашему инструменту разработки.

Все еще потеряно? Вы используете его для просмотра внутренних переменных.

введите описание изображения здесь

Действовать как заменитель debug_backtrace тоже введите описание изображения здесь

вы можете скачать здесь или Здесь

Всего документации и справки здесь

Кроме того, он также поддерживает почти всю инфраструктуру php

  • CodeIgniter
  • Drupal
  • Symfony
  • Symfony 2
  • WordPress
  • Yii
  • Структура
  • Zend Framework

Все лучшее....:)

Ответ 3

На ум приходят три вещи:

  • Настройте IDE, чтобы вы могли отлаживать PHP script по строкам
  • Добавьте некоторые записи в script
  • Ищите длинные запросы в MySQL

Отладка опции №2 является самой простой. Поскольку это выполняется как задание cron, вы добавляете в script:

кучу echo
<?php

function log_message($type, $message) {
    echo "[{strtoupper($type)}, {date('d-m-Y H:i:s')}] $message";
}

log_message('info', 'Import script started');

// ... the rest of your script

log_message('info', 'Import script finished');

Затем запустите stdout в файл журнала в команде задания cron.

01 04 * * * php /path/to/script.php >> /path/to/script.log

Теперь вы можете добавить log_message('info|warn|debug|error', 'Message here') по всему script и по крайней мере получить представление о том, где проблема с производительностью.

Отладка опции № 3 - это просто работа по поиску в MySQL. Один из ваших запросов может занять много времени, и он может появиться в долгосрочной утилите запросов для MySQL.

Ответ 4

Используйте strace, чтобы узнать, что программа в основном делает с точки зрения системы. Он висит в операциях ввода-вывода и т.д.? strace должно быть первым, что вы пытаетесь решить при возникновении проблем с производительностью с любым видом приложения Linux. Никто не может скрыться от него!;)

Если вы узнаете, что программа зависает в связанных с сетью вызовах, таких как connect, readfrom и друзьях, что означает, что сетевая связь действительно зависает в какой-то момент при подключении или ожидании ответов, чем вы можете использовать tcpdump для проанализируйте это.

Используя приведенные выше методы, вы сможете найти наиболее распространенные проблемы с производительностью. Обратите внимание, что вы даже можете прикреплять к выполняемой задаче с помощью strace с помощью -p PID.


Если приведенные выше методы не помогают, я бы профилировал script с помощью xdebug. Вы можете анализировать выход профилировщика с помощью таких инструментов, как KCachegrind

Ответ 5

Хотя это не оговорено, и если моя догадка правильная, вы, кажется, имеете дело с записями по одному, но в одном большом cron.

то есть. Захватите запись # 1, как-нибудь внесите ее, добавьте к ней значение, переформатируйте ее, затем сохраните, затем перейдите к записи # 2

Я бы подумал о том, чтобы сломать большой cron. т.е.

Cron # 1: захватить все записи и кэшировать все важные данные локально (на этот сервер). Установите флаг, если этот этап достигнут.

Cron # 2: теперь у вас есть необходимые данные, munge и добавьте значение, кэш, который выводит. Установите флаг, если этот этап достигнут.

Cron # 3: переформатируйте эти данные и сохраните их. Удалите все файлы.

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

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

Ответ 6

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

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

В общем, хотя и не внешний инструмент, вы можете использовать разницу между двумя запросами microtime (TRUE) на временные разделы кода. Чтобы журнал был ограниченным, установите флаг и проверяйте только время, если флаг не уменьшился до нуля после сокращения для каждого такого события. Вы можете иметь отдельные флаги для отдельных сегментов кода или даже для разных временных интервалов в сегменте кода.

$flag['name'] = 10;  // How many times to fire
$slow['name'] = 0.5; // How long in seconds before it a problem?

$start = microtime(TRUE);
do_something($parameters);
$used  = microtime(TRUE) - $start;
if ( $flag['name'] && used >= $slow['name'] )
{
  logit($parameters);
  $flag['name']--;
}

Если вы выведете какой URL-адрес или другие данные/событие заняли много времени для обработки, вы можете позже выкопать этот конкретный элемент, чтобы узнать, можете ли вы узнать, как он вызывает проблемы в вашем коде.

Конечно, это предполагает, что отдельные элементы вызывают вашу проблему, а не просто общее замедление с течением времени.

EDIT:

Я (сейчас) вижу это производственный сервер. Это делает редактирование кода менее приятным. Вероятно, вы захотите интегрировать с кодом минимальный процесс, имеющий логику тестирования и, возможно, поддерживаемые теги/флаги и количества во внешнем файле.

setStart('flagname');
// Do stuff to be checked for speed here
setStop('flagname',$moredata);

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

Ответ 7

xdebug_print_function_stack - это вариант, но то, что вы также можете сделать, это создать "трассировку функции". Существуют три выходных формата. Один из них предназначен для чтения человеком, а другой - для компьютерных программ, поскольку его легче анализировать, а последний использует HTML для форматирования трассировки

http://www.xdebug.org/docs/execution_trace

Ответ 8

Хорошо, в основном у вас есть две возможности - это либо неэффективный PHP-код, либо неэффективный код MySQL. Судя по тому, что вы говорите, он, вероятно, вставляет в индексированную таблицу много записей отдельно, что приводит к увеличению времени вставки. Вы должны либо отключить индексы, либо перестроить их после вставки, либо оптимизировать код вставки.

Но об инструментах.

Вы можете настроить систему на автоматический журнал медленных запросов MySQL: https://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html

Вы также можете сделать то же самое с PHP-скриптами, но вам нужна среда PHP-FPM (и у вас, вероятно, есть Apache). https://rtcamp.com/tutorials/php/fpm-slow-log/

Эти инструменты очень мощные и универсальные.

P.S. 10-20 минут для 100 записей похоже на LOT.

Ответ 9

Вы можете использовать https://github.com/jmartin82/phplapse для записи активности приложения для определения времени.

Например, начните запись после n итераций с помощью:

phplapse_start();

И остановите его на следующей итерации с помощью:

phplapse_stop();

С помощью этого процесса вы создали моментальный снимок выполнения, когда все кажется медленным.

(Я автор проекта, не стесняйтесь обращаться ко мне, чтобы улучшить функциональность)

Ответ 10

У меня есть аналогичная вещь, работающая каждую ночь (задание cron для обновления моей базы данных). Я нашел наиболее надежный способ отладки - настроить таблицу журналов в базе данных и регулярно вставлять/обновлять строку json, содержащую многомерный массив, с информацией о каждой записи и любой полезной информацией, которую вы хотите знать о каждой записи. Таким образом, если ваша работа cron не закончится, у вас все еще есть подробная информация о том, где она встала и что произошло на этом пути. Затем вы можете написать простую страницу, чтобы вытащить строку json, вернуть ее обратно в массив и распечатать полезные данные на странице, включая время и пройденные тесты и т.д. Когда вы видите что-то как проблему, вы можете сконцентрироваться на том, чтобы добавить больше информации из этой области в строку json.

Ответ 11

Регулярная команда "top" может показать вам, если использование процессора php или mysql является узким местом. Если нет, то задержки могут быть вызваны http-вызовами.

Если использование процессора mysqld низкое, но постоянное, то это может быть узким местом использования диска.

Кроме того, вы можете проверить использование полосы пропускания, установив и используя "спидометр" или другие инструменты.