XHProf: профилирование PHP
Date April 27th, 2012 Author Vitaly Agapov
Если приходится иметь дело с web-приложениями, написанными на php, то надо быть готовым разбираться с тем, почему приложение работает медленно, откуда растут ноги у тормозов, почему растёт использование системных ресурсов при увеличении нагрузки и так далее. Тут очень пригодятся инструменты, позволяющие собрать кое-какую статистику о различных аспектах работы приложения.
Особую прелесть приобретает этот процесс, если ты не являешься автором приложения, и оно представляет для тебя просто большой закрытый чёрный ящик. Тогда профилирование приложения без тщательного исследования кода позволит проделать в чёрном ящике дырочку для нашего любопытного взгляда.
Сегодня мы посмотрим на opensource-решение от компании Facebook – XHProf. Исходники были открыты в 2009-м году, правда с тех пор проект практически не развивается.
Профайлер позволяет произвести декомпозицию работы приложения до вызовов отдельных методов со сбором статистики по времени их отработки и использованию системных ресурсов. То есть если проблема в каком-то участке кода присутствует, то мы её найдем. Или хотя бы локализуем с определённой точностью.
То, что я напишу в этой статейке, будет иметь и общую информацию, но в большой степени всё-таки будет касаться частного случая – профилирования приложения, работающего в php-fpm, стоящего за nginx'ом. И всё это под Ubuntu 10.04.
Установка XHProf
Если речь идёт об Ubuntu (а моя речь именно о ней), то самым простым способом поставить XHProf будет PPA от Brian Mercer. Он же не так давно помог нам поставить и сам php-fpm на Ubuntu 10.04.
sudo add-apt-repository ppa:brianmercer/php5-xhprof sudo apt-get update sudo apt-get install php5-xhprof sudo /etc/init.d/php5-fpm restart php -m | grep xhprof
Последняя команда покажет нам наличие модуля xhprof в списке модулей PHP. Если он есть, то всё ок.
Если речь идёт не про Ubuntu (впрочем, для неё это тоже справедливо), то можно поставить XHProf из PECL или собрать вручную.
Установка из PECL:
pecl install xhprof-0.9.2
Установка вручную:
wget http://pecl.php.net/get/xhprof-0.9.2.tgz tar -xzvf xhprof-0.9.2.tgz cd xhprof-0.9.2 phpize ./configure --with-php-config=/usr/bin/php-config make && make test && make install
И при ручной уствноке надо в php.ini добавить расширение:
extension=xhprof.so xhprof.output_dir=/tmp
Установка graphviz
Для создания наглядных симпатичных диаграмм, визуализирующих цепочки вызовов функций в процессе работы приложения, на понадобится пакет graphviz. В Ubuntu он есть в репозиториях:
sudo apt-get install graphviz
Настройка XHProf
Для профилирования надо включить в приложение библиотеки из поставки xhprof и вызвать функцию xhprof_enable. Так как профилировать обычно нужно не все запросы, а выборочные, то можно сделать условие по наличию в заголовках запроса cookie определённого вида. В разных примерах в других публикациях обычно используется cookie xhprof. Самый простой способ добавить нужный код – это воспользоваться директивами auto_prepend_file и auto_append_file в php.ini.
Создадим файл /usr/share/php5-xhprof/header.php:
<?php if(isset($_COOKIE['xhprof'])){ if (extension_loaded('xhprof')) { $utils_path = "/usr/share/php5-xhprof/xhprof_lib/utils/"; include_once $utils_path.'xhprof_lib.php'; include_once $utils_path.'xhprof_runs.php'; xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY); } } ?>
Создадим файл footer.php:
<?php if(isset($_COOKIE['xhprof'])){ if (extension_loaded('xhprof')) { $profiler_namespace = 'someapp'; $xhprof_data = xhprof_disable(); $xhprof_runs = new XHProfRuns_Default(); $run_id = $xhprof_runs->save_run($xhprof_data, $profiler_namespace); $profiler_url = sprintf('http://mysite:81/index.php?run=%s&source=%s', $run_id, $profiler_namespace); echo '<a href="'.$profiler_url.'">XHProf</a>'; } } ?>
Этот кусок кода, который будет отрабатывать в конце обработки запроса, сохранит собранные данные и добавит в конце ссылку на страницу профайлера. URL, само собой, надо поправить на тот, который приведёт нас на нужный виртуал хост. Об этом чуть позже.
Чтобы эти сниппеты срабатывали в нужные нам моменты, надо добавить в php.ini (в моём случае это /etc/php5/fpm/php.ini) строки:
auto_prepend_file = /usr/share/php5-xhprof/header.php auto_append_file = /usr/share/php5-xhprof/footer.php
Само собой, можно вставлять соответствующие куски прямо в код страницы, чтобы профайлить не всё приложение целиком, а только какую-то его часть.
Настройка nginx
Для просмотра результатов профилирования в читабельном (и смотрибельном) виде, нужно настроить nginx. Я для этих целей сделал отдельный virtual-host, и это, само собой, не единственное возможное решение.
server { listen 81; server_name mysite; root /usr/share/php5-xhprof/xhprof_html; access_log /var/log/nginx/xhprof.access.log; location ~ \..*/.*\.php$ { return 403; } location / { index index.php; } location ~ \.php$ { fastcgi_pass unix:/tmp/phpfpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include /etc/nginx/fastcgi_params; } }
Проверяем
Для установки cookie xhprof можно воспользовать плагином для Firefox – Cookies Manager +. С помощью этого инструмента создаём новую куку, у которой в имени указываем xhprof, в содержимом – что угодно, а в узле – наш FQDN, с которым мы ходим на сайт.
После этого заходим на сайт и видим внизу страницы ссылку на профайл.
Если последнее утверждение истинно, то:
Вуаля!
Автоматизация
Бывают ситуации, когда приложение работает нормально, а проблемы начинаются в определеное время или вообще бессистемно. И хочется нам иметь результаты профилирования в исторической, так сказать, перспективе. Чтобы можно было посмотреть, как работало приложение, скажем, вчера в десять вечера.
Для этого можно пошаманить с header.php и footer.php, придумав хитрые условия. Например, рандомный запуск профайлера для каждого сотого запроса.
header.php:
if (rand(1, 100) == 1) { $xhprof_on = true; ... }
footer.php:
if ($xhprof_on) { $xhprof_data = xhprof_disable(); ... }
Но мы придумали более изящное (а может быть – более костыльное и кривое, кому как покажется) решение.
Для этого на любом сервере (хоть бы и на том же самом) с помощью cron с любой периодичностью запускаем команду:
/usr/bin/wget –no-cookies –header "Cookie: xhprof=1" 'http://mysite/' -o /dev/null -O /mnt/tmpfs/$(/bin/date \+\%Y\%m\%d_\%H\%M\%S)
Тогда на каждый из этих запросов можно будет посмотреть профайл. Ссылку можно либо взять из самой скаченной и сложенной в tmpfs страницы, либо посмотрев файлы с профилями, складывающиеся в xhprof.output_dir. В нашем случае это /tmp. Там при профилировании создаются текстовые файлы вида:
4f9a53e1b44f9.someapp
Хэш из названия файла можно подставить в url вида:
http://mysite:81/callgraph.php?run=4f9a53e1b44f9&source=someapp
Drupal предоставляет несколько инструментов для взаимодействия с XHProf. Первый – это плагин XHProf (http://drupal.org/project/XHProf), который позволяет отказаться от нативного веб-интерфейса XHProf, от дополнительных виртуальных хостов. И ещё он реализует разные приятные плюшки.
Но мне больше нравится более стандартный плагин Devel, который в своих настройках (admin/config/development/devel) позволяет включить XHProf, если оный модуль для PHP установлен в системе. В настройках также надо указать путь к библиотекам XHProf (/usr/share/php5-xhprof/) и относительный URL, по которому будут доступны результаты профилирования.
Но надо быть готовым к тому, что результат будет слегка зубодробительным.
Ссылки:
PECL:
http://pecl.php.net/package/xhprof
Хорошая статья про XHProf на FreeBSD:
http://adw0rd.ru/2010/freebsd-xhprof-php/
Статья на Хабре:
http://habrahabr.ru/post/78210/
Tags: Drupal, Nginx, PHP
Category:
Drupal, Nginx, PHP, Web-dev |
No comments »