perl debugger и mod_perl

25
Perl Debugger and mod_perl серия «книжко-малышко»

Upload: -mrrico

Post on 03-Nov-2014

18 views

Category:

Technology


0 download

DESCRIPTION

Прикручиваем perl debuuger к mod_perl

TRANSCRIPT

Page 1: Perl Debugger и mod_perl

Perl Debugger and

mod_perl

серия «книжко-малышко»

Page 2: Perl Debugger и mod_perl

Содержание Вступление Немного про mod_perl Проблема mod_perl Почему течёт память Варианты использования mod_perl Проблема отладки mod_perl Подключение debugger Собственные конфиги apache Тестовый запуск Прикручиваем perl debugger Тестовый запуск с perl debugger Сложности структуры Вашего проекта Материал и данные по тестированию

Page 3: Perl Debugger и mod_perl

ВступлениеВсегда есть упрямые. Спорить ни с кем не собираюсь. Любите отладку на

warn – ваше личное дело.Но, вместе с тем, просто задумайтесь над тем, что логи выполнения perl

кода нужны для «истории» работы, а не для поиска ошибок.

Кто знает perl debugger – знает perl

В этой презентации целью является - показать, как отлаживать ваш mod_perl проект так же, как если бы вы работали через debugger с cgi или pl скриптом.

Предполагается, что Вы уже знаете: команды perl debugger имеете общее представление о mod_perl имеете общее представление о httpd.conf

Так же, рассчитываю, что у Вас под рукой уже есть рабочее приложение под mod_perl, которое и станет нашим полигоном для испытаний ;)

Page 4: Perl Debugger и mod_perl

Немного про mod_perlmod_perl – это модуль к веб серверу Apache.

Единственное его назначение – это подгрузить ваш perl-код сразу в каждый чилд apache. Такой подход позволяет экономить время на компиляции. Получается весьма быстро.

Достигается это тем, что весь код как бы «оборачивается» стандартным для mod_perl описанием, и итоговый код представляет собой единый листинг* с кодом вашего приложения указанным для обработки в httpd.conf.

*Именно по этой причине, вы не можете обращаться к секции __DATA__ ваших скриптов.

Есть возможность указывать сколько request (число) должен обработать каждый чилд перед тем, как «перезапуститься». Т.о. решается проблема «течки» памяти mod_perl.

Если выставить, что каждый чилд обрабатывает только 1 запрос и умирает, то вы получите некий эквивалент классического CGI.

Page 5: Perl Debugger и mod_perl

Проблема mod_perl

Единственная, действительно неразрешимая проблема mod_perl, так это то, что mod_perl просто «ускоритель» и ни чего более.

А это означает, что написать приложение под mod_perl можно абсолютно не читаемо, так как Вас никто не ограничивает.

Поскольку в perl нет инструмента более мощного для чтения чужого кода, чем perl debugger, я поражён тем, что тема практически не раскрыта в рунете.

Если Вы хотите иметь (по мимо высокой скорости) и удобную, читаемую структуру кода, обратите своё внимание на перловый фреймворк Catalyst. Здесь Вам и MVC, и возможность переключаться между работой под mod_perl и FastCGI без изменения кода приложения. Да и отлаживается он без дополнительных ухищрений. Большое количество плагинов, отличная документация. В общем всё, чтобы Вы остались довольны.

Page 6: Perl Debugger и mod_perl

Почему течёт память

В общем случае, после появления чилда apache, он уже будет содержать скомпиленный код вашего приложения. При обработке разных запросов, для каждой функции/метода в вашем приложении будет резервироваться память. И если метод для одного запроса потребовал 1Мб памяти, а для следующего ему потребовалось всего 500Kb, то за этим методом/процессом всё равно останется зарезервированным 1Mb оперативной памяти. Так как разные запросы требуют обработки разного объёма данных, получается, что чилд apache «нажирается».

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

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

Page 7: Perl Debugger и mod_perl

Варианты использования mod_perlНа практике, я встречал 3 вида использования mod_perl:1. mod_perl подвязывается непосредственно к скриптамВот пример httpd.conf<IfModule mod_perl.c>

Alias /developer/ /path/developer/ <Location /developer>

SetHandler perl-scriptPerlHandler ModPerl::RegistryOptions ExecCGIPerlSendHeader Onallow from all

</Location></IfModule>

Здесь указывается, что при обращении по пути url/developer/… задействовать скрипты, которые находятся в папке /path/developer (см Alias).

*отдельно отмечу, что в конфигах старых версий apache может встречаться

PerlHandler Apache::PerlRun

Page 8: Perl Debugger и mod_perl

Варианты использования 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!

Page 9: Perl Debugger и mod_perl

Варианты использования mod_perl

2. mod_perl подвязывается к перл модулю, который обрабатывает $r->uri() и принимает решение какой ответ дать.

Вот пример httpd.conf:<IfModule mod_perl.c>

PerlModule MyPackage::Main

<Location />

SetHandler perl-script

PerlHandler MyPackage::Main

</Location>

</IfModule>

<Location /> указывает, что нужно отдавать/обрабатывать любой request модулю MyPackage::Main

Page 10: Perl Debugger и mod_perl

Варианты использования 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/){...

...}

Page 11: Perl Debugger и mod_perl

Варианты использования mod_perl

3. mod_perl реализуется как симбиоз вариантов 1 и 2.

Сложно сказать, какой путь для Вас более оптимален. Пожалуй чаще, встречается вариант2.

Page 12: Perl Debugger и mod_perl

Проблема отладки mod_perl

Как уже понятно, речь идёт о подключении perl debugger к perl коду в чилде apache.

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

Особенно забавно, что многие отлаживают на warn продакшн код. И если речь идёт о часто используемом месте проекта, то даже за несколько секунд лог может получиться ёмким. Добавим к этому «ошибка появляется редко» и, получается, что времени на локализацию проблемы уходит много.

С perl debugger вы находитесь внутри исполняемой программы и можете без труда «с первого захода» успешно локализовать код с ошибкой.

Page 13: Perl Debugger и mod_perl

Подключение debugger

Для отладки нам потребуется:

Создать собственные конфиги apache (в home) Прописать обработку каждого запроса через perl отладчик Запустить httpd процесс в non-forking режиме (один чилд) с

обработкой через perl debugger и нашими конфигами Запросить url через браузер, и приступить к отладке Корректно выйти из отладчика

Итак, приступим.

Page 14: Perl Debugger и mod_perl

Собственные конфиги 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

Page 15: Perl Debugger и mod_perl

Собственные конфиги 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

Page 16: Perl Debugger и mod_perl

Собственные конфиги 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

Но это ещё не всё.

Page 17: Perl Debugger и mod_perl

Собственные конфиги 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

Page 18: Perl Debugger и mod_perl

Собственные конфиги apacheИтак, мы сделали описание для apache, но ещё никак не затронули

описание виртхоста, который как раз и работает у нас с mod_perl. Как было сказано выше, это описание может быть и в самом httpd.conf, так и в отдельном файле. Я рассматриваю случай отдельного описания в mysite.conf. Его содержимое изначально будет (к примеру):

<VirtualHost *:80>

ServerName mysite.ru:80

CustomLog /var/log/access.log combined

ErrorLog /var/log/error.log

DocumentRoot /site

....

<IfModule mod_perl.c>

PerlModule MyPackage::Main

<Location />

SetHandler perl-script

PerlHandler MyPackage::Main

</Location>

</IfModule>

</VirtualHost>

Содержимое должно быть вам понятно.

Page 19: Perl Debugger и mod_perl

Собственные конфиги apacheОтредактируем его (~/ mysite.conf) до вида:<VirtualHost *:3000>

ServerName mysite.ru:3000

CustomLog /home/yesiam/log/access.log combined

ErrorLog /home/yesiam/log/error.log

DocumentRoot /site

....

<IfModule mod_perl.c>

PerlModule MyPackage::Main

<Location />

SetHandler perl-script

PerlHandler MyPackage::Main

</Location>

</IfModule>

</VirtualHost>

Не забудьте создать папку ~/log

Итак, мы скопировали конфиги к себе в хомяк, отредктировали их так, что: при запуске мы будем слушать порт 3000 все логи, pid-файлы и lock-файлы будут храниться в нашем хомяке

Осталось сделать тестовый запуск.

Page 20: Perl Debugger и mod_perl

Тестовый запускВсе обращения, что до этого вы делали на 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 на отдельном порту. Вам не потребовалась помощь админа, или какие-то особые права.

Page 21: Perl Debugger и mod_perl

Прикручиваем perl debuggerТеперь нам осталось подключить perl debugger в каждый чилд apache. А

поскольку мы запускаемся в non-forking режиме, то – только к одному.Для этого добавим в вверх описания виртхоста:

<VirtualHost *:3000>ServerName mysite.ru:3000CustomLog /home/yesiam/log/access.log combinedErrorLog /home/yesiam/log/error.logDocumentRoot /site

<IfDefine PERLDB> <Perl>

use Apache::DB ();Apache::DB->init;

</Perl> <Location />

PerlFixupHandler Apache::DB</Location>

</IfDefine>....<IfModule mod_perl.c>

PerlModule MyPackage::Main<Location />

SetHandler perl-scriptPerlHandler MyPackage::Main

</Location></IfModule>

</VirtualHost>

Page 22: Perl Debugger и mod_perl

Тестовый запуск с 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 отладчика.

Page 23: Perl Debugger и mod_perl

Тестовый запуск с perl debuggerВ отличие от стандартной работы с отладчиком, вы можете указать

команду «с» и при этом ваш чилд apache сразу вернёт ответ браузеру (если в коде не встречается $DB::signal). И сделать ещё одно обращение к урл. При этом, отладчик снова остановится на методе handler вашего модуля.

Так же стоит уделить внимание корректному выходу из отладчика. Помните, когда вы запустили apache (httpd -X -D PERLDB -f ~/httpd.conf), то он сообщил Вам номер процесса в системе (initialized in child 17524). Так вот, корректный выход будет таким (номер процесса, конечно индивидуален):

DB<3> !! kill 17524DB<4> q

Или есть такой вариант: DB<3> p $$17524 DB<4> !! kill 17524 DB<5> q

Т.е. вы сначала «убиваете» процесс чилда apache, и потом выходите из отладки.

*команда «!!» в отладчике передаёт последующие аргументы в shell

Page 24: Perl Debugger и mod_perl

Сложности структуры Вашего проектаКонечно, Ваш проект может быть не так прост. У Вас скорее всего есть

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

Page 25: Perl Debugger и mod_perl

Материал и данные по тестированию

За основу было взято описание процесса отладки с http://perl.apache.org/docs/1.0/guide/debug.html

И проверено на практике.

Тестирование проводилось на FreeBSD 6.2 и Apache/2.2.11