Слайд 1Perl Debugger
and
mod_perl
серия «книжко-малышко»
Слайд 2Содержание
Вступление
Немного про mod_perl
Проблема mod_perl
Почему течёт память
Варианты использования mod_perl
Проблема отладки mod_perl
Подключение debugger
Собственные
конфиги apache
Тестовый запуск
Прикручиваем perl debugger
Тестовый запуск с perl debugger
Сложности структуры Вашего проекта
Материал и данные по тестированию
Слайд 3Вступление
Всегда есть упрямые. Спорить ни с кем не собираюсь. Любите отладку
на warn – ваше личное дело.
Но, вместе с тем, просто задумайтесь над тем, что логи выполнения perl кода нужны для «истории» работы, а не для поиска ошибок.
Кто знает perl debugger – знает perl
В этой презентации целью является - показать, как отлаживать ваш mod_perl проект так же, как если бы вы работали через debugger с cgi или pl скриптом.
Предполагается, что Вы уже знаете:
команды perl debugger
имеете общее представление о mod_perl
имеете общее представление о httpd.conf
Так же, рассчитываю, что у Вас под рукой уже есть рабочее приложение под mod_perl, которое и станет нашим полигоном для испытаний ;)
Слайд 4Немного про mod_perl
mod_perl – это модуль к веб серверу Apache.
Единственное
его назначение – это подгрузить ваш perl-код сразу в каждый чилд apache. Такой подход позволяет экономить время на компиляции. Получается весьма быстро.
Достигается это тем, что весь код как бы «оборачивается» стандартным для mod_perl описанием, и итоговый код представляет собой единый листинг* с кодом вашего приложения указанным для обработки в httpd.conf.
*Именно по этой причине, вы не можете обращаться к секции __DATA__ ваших скриптов.
Есть возможность указывать сколько request (число) должен обработать каждый чилд перед тем, как «перезапуститься». Т.о. решается проблема «течки» памяти mod_perl.
Если выставить, что каждый чилд обрабатывает только 1 запрос и умирает, то вы получите некий эквивалент классического CGI.
Слайд 5Проблема mod_perl
Единственная, действительно неразрешимая проблема mod_perl, так это то, что mod_perl
просто «ускоритель» и ни чего более.
А это означает, что написать приложение под mod_perl можно абсолютно не читаемо, так как Вас никто не ограничивает.
Поскольку в perl нет инструмента более мощного для чтения чужого кода, чем perl debugger, я поражён тем, что тема практически не раскрыта в рунете.
Если Вы хотите иметь (по мимо высокой скорости) и удобную, читаемую структуру кода, обратите своё внимание на перловый фреймворк Catalyst. Здесь Вам и MVC, и возможность переключаться между работой под mod_perl и FastCGI без изменения кода приложения. Да и отлаживается он без дополнительных ухищрений. Большое количество плагинов, отличная документация. В общем всё, чтобы Вы остались довольны.
Слайд 6Почему течёт память
В общем случае, после появления чилда apache, он уже
будет содержать скомпиленный код вашего приложения. При обработке разных запросов, для каждой функции/метода в вашем приложении будет резервироваться память. И если метод для одного запроса потребовал 1Мб памяти, а для следующего ему потребовалось всего 500Kb, то за этим методом/процессом всё равно останется зарезервированным 1Mb оперативной памяти. Так как разные запросы требуют обработки разного объёма данных, получается, что чилд apache «нажирается».
Конечно, есть много других моментов, скажем связанные с ссылками. Но их все можно устранить.
Как уже понятно, вопрос времени – когда процесс станет до неприличия жирным. Поэтому и есть такой параметр в настройках apache, отвечающий за смерть чилда после обработки определённого количества запросов.
Слайд 7Варианты использования mod_perl
На практике, я встречал 3 вида использования mod_perl:
1. mod_perl
подвязывается непосредственно к скриптам
Вот пример httpd.conf
Alias /developer/ /path/developer/
SetHandler perl-script
PerlHandler ModPerl::Registry
Options ExecCGI
PerlSendHeader On
allow from all
Здесь указывается, что при обращении по пути url/developer/… задействовать скрипты, которые находятся в папке /path/developer (см Alias).
*отдельно отмечу, что в конфигах старых версий apache может встречаться
PerlHandler Apache::PerlRun
Слайд 8Варианты использования mod_perl
По пути /path/developer у нас может быть скрипт типа
simple_example.pl с контентом:
use Apache2::Request;
my $r = shift;
$r->content_type('text/plain');
$r->print("mod_perl rules!\n");
Или в более традиционном виде:
use Apache2::Const -compile => qw(REDIRECT NOT_FOUND);
sub handler{
my $r = shift;
$r->send_http_header('text/plain');
print "mod_perl rules!\n";
return OK;
}
1;
И в одном и в другом случае, в браузере по пути url/develiper/imple_example.pl мы увидим:
mod_perl rules!
Слайд 9Варианты использования mod_perl
2. mod_perl подвязывается к перл модулю, который обрабатывает $r->uri()
и принимает решение какой ответ дать.
Вот пример httpd.conf:
PerlModule MyPackage::Main
SetHandler perl-script
PerlHandler MyPackage::Main
указывает, что нужно отдавать/обрабатывать любой request модулю MyPackage::Main
Слайд 10Варианты использования mod_perl
В каком-то смысле, классический пример контента для MyPackage::Main
package MyPackage::Main;
use
strict;
use Apache2::Request;
use MyPackage::Config;
use Apache2::Const -compile => qw(REDIRECT NOT_FOUND);
use Apache2::Cookie;
sub handler{
my $r = shift;
my $req = Apache2::Request->new($r);
my $uri = $r->uri();
my $cfg = MyPackage::Config->new();
my $page_controller = undef;
my $answer = undef;
if($uri =~ /^\/foo\/bar/){
...
...
}
Слайд 11Варианты использования mod_perl
3. mod_perl реализуется как симбиоз вариантов 1 и 2.
Сложно
сказать, какой путь для Вас более оптимален. Пожалуй чаще, встречается вариант2.
Слайд 12Проблема отладки mod_perl
Как уже понятно, речь идёт о подключении perl debugger
к perl коду в чилде apache.
Так как рунете сложно найти описание подобного механизма, многие предпочитают использовать отладку на warn. Т.е. расставляют warn, запускают, смотрят лог, перемещают warn, запускают программу и т.д. до тех пор, пока ошибка не локализуется достаточно, чтобы программист её нашёл.
Особенно забавно, что многие отлаживают на warn продакшн код. И если речь идёт о часто используемом месте проекта, то даже за несколько секунд лог может получиться ёмким. Добавим к этому «ошибка появляется редко» и, получается, что времени на локализацию проблемы уходит много.
С perl debugger вы находитесь внутри исполняемой программы и можете без труда «с первого захода» успешно локализовать код с ошибкой.
Слайд 13Подключение debugger
Для отладки нам потребуется:
Создать собственные конфиги apache (в home)
Прописать обработку
каждого запроса через perl отладчик
Запустить httpd процесс в non-forking режиме (один чилд) с обработкой через perl debugger и нашими конфигами
Запросить url через браузер, и приступить к отладке
Корректно выйти из отладчика
Итак, приступим.
Слайд 14Собственные конфиги apache
Рассмотрим следующий вариант работы apache:
1 – определение вашего приложения
в обработке mod_perl
2 – появление чилдов apache с проинициализированным кодом вашего perl приложения
3 – запрос пользователя, который перенаправляется apache на один из своих child
Apache
Ваше perl приложение
mod_perl
WEB
C
H
I
L
D
C
H
I
L
D
C
H
I
L
D
C
H
I
L
D
1
2
3
Слайд 15Собственные конфиги apache
Как было сказано вначале, я считаю, что у Вас
уже есть рабочее mod_perl приложение.
Вам необходимо найти httpd.conf
Сделать это можно так:
$ httpd –V
Конфиг apache будет по пути HTTPD_ROOT.’/’. SERVER_CONFIG_FILE
Например, если HTTPD_ROOT="/usr/local" и SERVER_CONFIG_FILE="etc/apache22/httpd.conf",
то полный путь к конфигу будет /usr/local/etc/apache22/httpd.conf
Откопируем его в наш хомяк:
$ cp /usr/local/etc/apache22/httpd.conf ~/httpd.conf
Слайд 16Собственные конфиги apache
Откройте для редактирования ~/httpd.conf Обратите внимание на параметр Listen.
Его значение означает порт, который слушает apache.
Обычно это 80-й, 81-й порт. Порты, как известно, до 1024-го привилегированные. Поэтому в нашем конфиге поставим любой свободный порт, а-ля:
Listen 3000
Пусть ваш username в системе – yesiam. И хомяк по пути /home/yesiam.
Меняем параметры:
ErrorLog "/home/yesiam/httpd-error.log"
CustomLog "/home/yesiam/httpd-access.log" combined
Но это ещё не всё.
Слайд 17Собственные конфиги apache
Хороший админ не описывает виртхосты в самом httpd.conf. Для
этого, он использует такой параметр, как:
Include etc/apache22/Includes/*.conf
В вашем случае, путь может отличаться.
Здесь говорится: «дополни данные конфига, содержимым файлов с расширением conf по пути $HTTPD_ROOT/etc/apache22/Includes/»
Если у вас есть такая директива, то ищите описания виртхостов в указанной папке и откопируйте в хомяк нужное описание. Пусть это будет файл mysite.conf.
$ cp /usr/local/etc/apache22/Includes/mysite.conf ~/mysite.conf
В ~/httpd.conf поменяйте:
Include etc/apache22/Includes/*.conf
на
Include /home/yesiam/mysite.conf
И, последний штрих в ~/httpd.conf:
PidFile /home/yesiam/apache.pid
LockFile /home/yesiam/accept.lock
Слайд 18Собственные конфиги apache
Итак, мы сделали описание для apache, но ещё никак
не затронули описание виртхоста, который как раз и работает у нас с mod_perl. Как было сказано выше, это описание может быть и в самом httpd.conf, так и в отдельном файле. Я рассматриваю случай отдельного описания в mysite.conf. Его содержимое изначально будет (к примеру):
ServerName mysite.ru:80
CustomLog /var/log/access.log combined
ErrorLog /var/log/error.log
DocumentRoot /site
....
PerlModule MyPackage::Main
SetHandler perl-script
PerlHandler MyPackage::Main
Содержимое должно быть вам понятно.
Слайд 19Собственные конфиги apache
Отредактируем его (~/ mysite.conf) до вида:
ServerName mysite.ru:3000
CustomLog /home/yesiam/log/access.log
combined
ErrorLog /home/yesiam/log/error.log
DocumentRoot /site
....
PerlModule MyPackage::Main
SetHandler perl-script
PerlHandler MyPackage::Main
Не забудьте создать папку ~/log
Итак, мы скопировали конфиги к себе в хомяк, отредктировали их так, что:
при запуске мы будем слушать порт 3000
все логи, pid-файлы и lock-файлы будут храниться в нашем хомяке
Осталось сделать тестовый запуск.
Слайд 20Тестовый запуск
Все обращения, что до этого вы делали на http://mysite.ru:80 или
http://mysite.ru:81 (зависит от Listen в изначальном httpd.conf) к этому apache должны быть доступны и при обращении к http://mysite.ru:3000
Пусть mod_perl у вас обрабатывал урл http://mysite.ru:80/12345/rss.xml
Запускаем «наш» apache в non-forking режиме (т.е. у вас будет только 1 чилд) с нашими конфигами:
$ httpd -X -k start -f ~/httpd.conf
И заходим по урл http://mysite.ru:3000/12345/rss.xml
Вы должны увидеть точно такой же ответ в браузере, как если бы Вы зашли на http://mysite.ru:80/12345/rss.xml
Если у вас произошла ошибка, посмотрите файлы логов ошибок в своём хомяке. Проблема, если и будет, должна решиться легко.
Заметьте, Вы не мешаете работе продакшн кода! И, при этом, локализовали чилд apache на отдельном порту. Вам не потребовалась помощь админа, или какие-то особые права.
Слайд 21Прикручиваем perl debugger
Теперь нам осталось подключить perl debugger в каждый чилд
apache. А поскольку мы запускаемся в non-forking режиме, то – только к одному.
Для этого добавим в вверх описания виртхоста:
ServerName mysite.ru:3000
CustomLog /home/yesiam/log/access.log combined
ErrorLog /home/yesiam/log/error.log
DocumentRoot /site
use Apache::DB ();
Apache::DB->init;
PerlFixupHandler Apache::DB
....
PerlModule MyPackage::Main
SetHandler perl-script
PerlHandler MyPackage::Main
Слайд 22Тестовый запуск с perl debugger
Итак, запускаем:
$ httpd -X -D PERLDB -f
~/httpd.conf
И, видим приветствие:
[notice] Apache::DB initialized in child 17524
Набираем в браузере урл http://mysite.ru:3000/12345/rss.xml и видим, что отладчик остановился в handler нашего MyPackage::Main
MyPackage::Main::handler(/site/MyPackage/Main.pm:14):
14: my $r = shift;
Всё. Теперь Вы можете приступить к отладке используя стандартные команды perl отладчика.
Слайд 23Тестовый запуск с perl debugger
В отличие от стандартной работы с отладчиком,
вы можете указать команду «с» и при этом ваш чилд apache сразу вернёт ответ браузеру (если в коде не встречается $DB::signal). И сделать ещё одно обращение к урл. При этом, отладчик снова остановится на методе handler вашего модуля.
Так же стоит уделить внимание корректному выходу из отладчика. Помните, когда вы запустили apache (httpd -X -D PERLDB -f ~/httpd.conf), то он сообщил Вам номер процесса в системе (initialized in child 17524). Так вот, корректный выход будет таким (номер процесса, конечно индивидуален):
DB<3> !! kill 17524
DB<4> q
Или есть такой вариант:
DB<3> p $$
17524
DB<4> !! kill 17524
DB<5> q
Т.е. вы сначала «убиваете» процесс чилда apache, и потом выходите из отладки.
*команда «!!» в отладчике передаёт последующие аргументы в shell
Слайд 24Сложности структуры Вашего проекта
Конечно, Ваш проект может быть не так прост.
У Вас скорее всего есть Nginx, который может балансировать между несколькими apache на нескольких серверах. Сложность будет в том случае, если на уровне nginx.conf у вас прописано изменение порядка или набора uri аргументов. К примеру для сайта globalsite.ru (вымышленное) в nginx.conf может быть:
server {
listen 80;
server_name globalsite.ru www.globalsite.ru;
location /archives/ {
if ($uri ~ (\d+)/rss.xml){
set $q $1;
rewrite / /rss/$q;
proxy_pass http://mysite.ru:80;
break;
}
....
Т.е. обращения на http://globalsite.ru/archives/12345/rss.xml перенаправляются на http://mysite.ru/rss/12345 При этом, если вы тестируете mod_perl на mysite.ru помните о реврайтах на уровне Nginx. И, в нашем случае, за http://globalsite.ru/archives/12345/rss.xml будет отвечать http://mysite.ru:3000/rss/12345
Слайд 25Материал и данные по тестированию
За основу было взято описание процесса отладки
с http://perl.apache.org/docs/1.0/guide/debug.html
И проверено на практике.
Тестирование проводилось на FreeBSD 6.2 и Apache/2.2.11