Xpoint
   [напомнить пароль]

Программирование::Perl::Программирование под mod_perl - F.A.Q.

Что такое mod_perl, какие у него преимущества/недостатки?
mod_perl привязывает Perl к каждому процессу Apache. Это позволяет Apache быстрее выполнять программы на Perl, поскольку не нужно вызывать интерпретатор и модули надо загружать и компилировать только один раз на весь процесс. Обычно mod_perl используется как замена mod_cgi (стандартный CGI интерфейс) для ускорения выполнения программ, но возможностей у mod_perl гораздо больше. С помощью mod_perl можно поставить свой обработчик на любую часть обработки запроса. Таким образом были написаны обработчики на Perl, заменяющие почти каждый модуль Apache. Можно также динамически создавать конфигурацию сервера. Ещё одно преимущество mod_perl это возможность делать собственные подзапросы серверу (что в mod_cgi делалось через обходным путем через LWP).

Есть конечно и недостатки. Поскольку процесс Perl живёт дольше чем обычно и хранит при этом информацию о всех загруженых модулях, то расход памяти получается существенно выше. Кроме того нельзя исходить из того, что после выполнения программы Perl закончится и рабочая память очистится, это произойдёт лишь про завершении процесса Apache. Из-за этого очень важно чистое программирование.
Как сделать версию Апача со статически встроенным mod_perl?
Возьмите с http://perl.apache.org/dist/ актуальную версию master source distribution для mod_perl. Вам потребуются также исходные тексты Апача, если у вас их нет, возьмите с http://www.apache.org/dist/httpd/.
  1. Распаковать исходники Апача:
    tar xzvf apache_x.x.x.tar.gz
  2. Распаковать исходники mod_perl:
    tar xzvf mod_perl-x.xx.tar.gz
  3. Перейти в подкаталог mod_perl и запустить конфигурацию:
    cd mod_perl-x.xx
    perl Makefile.PL APACHE_SRC=../apache_x.x.x/src \
       DO_HTTPD=1 USE_APACHI=1 EVERYTHING=1
    EVERYTHING=1 активирует все опции кроме экспериментальных. Полное описание этих опций вы можете найти на http://perl.apache.org/guide/install.html#Configuration_parameters.
  4. Создать, проверить и инсталировать mod_perl и Apache:
    make && make test && make install
Как инсталировать mod_perl под Windows?
Имейте в виду, что на данный момент mod_perl для Windows имеет статус alpha.

Для инсталяции mod_perl требуются уже инсталированые Apache и Perl (об установке Perl под Windows см. FAQ раздела Perl::Windows аспекты). Вызовите Perl Package Manager (обычно c:\Perl\bin\ppm.bat). Введите команду:
install <путь к mod_perl>/mod_perl.ppd
При этом путь может быть как локальный, если mod_perl.ppd у вас уже есть, так и URL (к примеру http://theoryx5.uwinnipeg.ca/ppmpackages/mod_perl.ppd для Perl 5.6 или http://theoryx5.uwinnipeg.ca/ppms/mod_perl.ppd для Perl 5.8). В любом случае нужна связь с интернетом!

Текущая версия инсталирует модуль в подкаталог Apache/modules под именем mod_perl.so.
Что надо установить в конфигурации Апача, чтобы выполнять скрипты под mod_perl?
Для подкаталогов с mod_perl нельзя использовать директиву ScriptAlias, поскольку эта автоматически устанавливает mod_cgi как хэндлер. Вместо этого поставьте:
<IfModule mod_perl.c>
        Alias /perl/ /my/scripts/directory/

        <Directory /my/scripts/directory>
                SetHandler perl-script
                PerlHandler Apache::Registry
                Options ExecCGI
                Allow from all
                PerlSendHeader on
        </Directory>
</IfModule>

PerlSendHeader on нужно, чтобы эмулировалось поведение mod_cgi, то есть вывод скрипта проверялся на наличие заголовка HTTP, в котором бы дополнялись недостающие строки. Это не нужно, если ваши скрипты посылают заголовок через $q->header() из CGI.pm или $r->send_http_header() из Apache.pm.
Как сделать, чтобы одни и те же скрипты можно было проверять как под mod_perl, так и под mod_cgi?
Надо сделать несколько имён для одного и того же подкаталога, для которых установить разные хэндлеры. Вот пример, в котором есть обычный подкаталог cgi-bin (mod_cgi), perl (mod_perl с хэндлером Apache::Registry) и cgi-perl (mod_perl с хэндлером Apache::PerlRun):
ScriptAlias /cgi-bin/ "/my/scripts/directory/" 

<Directory "/my/scripts/directory">
        AllowOverride None 
        Options None 
</Directory>

<IfModule mod_perl.c>
        Alias /perl/ "/my/scripts/directory/" 
       
        <Location /perl/*.pl>
                SetHandler perl-script 
                PerlHandler Apache::Registry 
                Options -Indexes ExecCGI 
                PerlSendHeader On 
        </Location>

        Alias /cgi-perl/ "/my/scripts/directory/" 
       
        <Location /cgi-perl/*.pl>
                SetHandler perl-script 
                PerlHandler Apache::PerlRun 
                Options -Indexes ExecCGI 
                PerlSendHeader On 
        </Location>
</IfModule>

Как предотвратить, что при запросе обычных страниц Apache с mod_perl расходует лишнюю память?
К сожалению Perl привязывается даже к тем процессам Apache, которые обрабатывают только обычные страницы или скрипты CGI. При этом неминуемо расходуется больше памяти чем со стандартным Apache. Решение проблемы - использовать два сервера, стандартный на порту 80 и сервер с mod_perl к примеру на порту 8200. При этом можно использовать стандартный сервер как прокси для запросов к mod_perl, так что для пользователя ничего не изменится.

Итак создаются две конфигурации Apache, стандартная httpd.conf и httpd-perl.conf, которая всключает mod_perl. В стандартной конфигурации требуются mod_rewrite и mod_proxy, так что уберите знак комментария со следущих строчек, если он есть:
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
AddModule mod_rewrite.c
AddModule mod_proxy.c

После этого в httpd.conf добавить:
RewriteEngine On
RewriteRule ^(.*\/perl\/.*)$ http://%{HTTP_HOST}:8200$1 [P]
RewriteRule ^(.*\/cgi\-perl\/.*)$ http://%{HTTP_HOST}:8200$1 [P]

И уже все запросы, в которых попадается подкаталог perl или cgi-perl, перенаправляются на порт 8200.
Как узнать текущее состояние mod_perl, загруженые модули итп?
Сделайте подкаталог /perl-status, который бы обрабатывался модулем Apache::Status:
<IfModule mod_perl.c>
        <Location /perl-status>
                SetHandler perl-script
                PerlHandler Apache::Status
                Order deny,allow
                Deny from all
                Allow from 127.0.0.1
        </Location>
</IfModule>

Вы можете ещё получить дополнительную информацию, к примеру о размере памяти, который занимает какая-то функция. Для некоторых страниц требуется модуль B::Size, который отсутствует среди стандартных модулей Перла (инсталяция: под Unix/Linux вызвать perl -MCPAN -eshell, под Windows ppm, в обеих случаях задать комманду install B::Size). В конфигурацию сервера нужно добавить директивы:
PerlSetVar StatusOptionsAll On
PerlSetVar StatusTerse On
PerlSetVar StatusTerseSize On
PerlSetVar StatusTerseSizeMainSummary On

Что делает Apache::Registry и в чём разница Apache::PerlRun?
Apache::Registry эмулирует среду CGI для скриптов, которые либо не предназначены для mod_perl, либо хотят остаться совместимыми с mod_cgi. Сам mod_perl может использовать только обработчики событий, то есть модули Перла включающие в себя функцию handler(). Обработчик Apache::Registry именно и делает то, что приводит программу к такому виду. При этом вся программа помещается в функцию handler(), кроме того программе прописывается имя пакета, которое создаётся из URI (программы под mod_perl не выполняются в пакете main!). После этого функция handler() вызывается как для обычного обработчика с объектом типа Apache как параметр (поэтому программы под mod_perl обычно начинаются с my $r=shift). Функция exit() заменяется на Apache::exit(), чтобы при завершении программы не завершился в придачу ещё и процесс Перла. Вот что получается в результате:

Исходная программа (/perl/test.pl):
my $r = shift;
$r->content_type("text/html");
$r->send_http_header();
print "Hello world!";

Результат:
package Apache::ROOT::perl::test_2epl;
use Apache qw(exit);

sub handler {
#line 1 test.pl
my $r = shift;
$r->content_type("text/html");
$r->send_http_header;
print "Hello world!";
}

Apache::PerlRun отличается от Apache::Registry тем, что в некоторых случаях позволяет использовать плохо написаные программы без изменений. В частности при завершении программы все её переменные удаляются и не создают ошибок при следущем выполнении (но не переменные модулей, загруженных этой программой!).
Чем программа под mod_perl отличается от обычной программы на CGI, какие могут возникнуть проблемы?
  • Нельзя использовать не инициализированые глобальные переменные, поскольку в них может быть значение с предыдущего вызова программы. Поэтому надо обязательно использовать use strict!
  • При использовании use и require программы загружаются лишь один раз на процесс Апача. Если файлы изменились, они не будут автоматически загружены заново! Apache::Registry и Apache::PerlRun проверяют дату последнего изменения для вашей программы и перезагружают её при надобности, но это не распространяется на файлы, которые вы загружаете внутри программы. Если у вас к примеру конфигурационный файл, который вы загружаете с помощью require, то вы должны сами позаботиться о перезагрузке.
  • Программа для Apache::Registry или Apache::PerlRun не может содержать тегов __END__ и __DATA__, поскольку она вставляется в функцию handler() и закрывающая скобка функции отрезается этими тегами.
  • При завершении программы следует вызывать не exit(), а Apache::exit(), поскольку первая завершает весь процесс Перла. Apache::Registry и Apache::PerlRun заменяют функцию exit() в именном пространстве программы, то есть заботиться об этом нужно только при написании собственных обработчиков.
  • Не следует менять значение переменных типа $SIG{__DIE__} или $/, которые распространяются на все модули, поскольку те же переменные будут использоваться другими программами на этом процессе Апача. Если значение надо менять, позаботьтесь о том, что исходное значение будет восстановлено, к примеру с помощью local:
    local $/ = ""; 
    
    
  • Вывод функций system(), exec() и open(PIPE,"|program") не обязательно станет посылаться на браузер, а лишь с определённой кофигурацией Перла.
Полезные ссылки
  1. Официальная страница mod_perl: http://perl.apache.org
  2. The mod_perl guide: http://perl.apache.org/guide/
  3. Mod_perl cookbook: http://www.modperlcookbook.org/
  4. mod_perl and The Perl Conference 2.0: http://modperl.com:9000/perl_conference/handout.html
Ссылки на F.A.Q. Perl-форумов
Powered by POEM™ Engine Copyright © 2002-2005