Ключевые слова:perl, fastcgi, web, (найти похожие документы)
From: Николай <http://kiev.pm.org/>
Date: Mon, 16 Dec 2007 14:31:37 +0000 (UTC)
Subject: FastCGI или mod_perl, пример оформления FastCGI скрипта на Perl
Оригинал: http://kiev.pm.org/?q=node/111
С января 2001 года сфера моей профессиональной деятельности тесно
связна с созданием web-сервисов, в основном аналитических.
Одной из технологий, используемых в работе, является mod_perl. FastCGI
не использовался ни разу. Почему? Как часто отвечают: "по
историческим причинам". А вот сейчас решил посмотреть в сторону
FastCGI подробней. Специфика нового проекта подразумевает наличие
frontend'да, например, nignx. "Нет, проблем", - говорю сам себе:
"frontend'ом будет nignx, а backend'ом - Apache". Но не так все
просто.
В рассылке по nignx, до того как было все разложено по полочкам в
различных документациях и заметках, часто задавались вопросы по
использованию PHP в режиме FastCGI. То есть люди массово избавлялись
от Apache mod_php, переходя не FastCGI. При этом, что в тот момент, не
знаю как сейчас, патч php-fpm (http://php-fpm.anight.org/) не был
включен в официальные исходники, так что многие пользовалось
spawn-fcgi от lighttpd.
Что это? Дань моде или нечто большее? Тем не-менее этот процесс
подтолкнул меня посмотреть подробней, какие есть у FastCGI
преимущества. Да, я знаю, mod_perl и mod_php координально отличаются в
области загрузки кода, но будем считать, что php акселераторы работают
хорошо и это не является причиной перехода с mod_php на FastCGI.
Известно, что процессы Apache с mod_perl очень прожорливы на память.
Может с FastCGI ее требуется меньше? Теоретически разница не должна
быть слишком большой: ведь под mod_perl можно все используемые модули
загрузить до начала создания дочерних процессов.
Стоп! Если мне не изменяет память, то mod_php так не может! Наверно
это и есть причина перехода с mod_php на FastCGI. Хм, но ведь и
spawn-fcgi в этом вопросе не помощник...
Тем не-менее с FastCGI решил разобраться до конца. Прописал в конфиге
nignx какой порт слушать и занялся perl. Для perl существует три
основных модуля FCGI, FCGI::ProcManager и FCGI::Spawn. (о FCGI::Async
и других разговор не ведем). Первый является основным, второй - это
менеджер процессов. Третий является надстройкой над первым двумя и
предназначен для запуска скриптов через require, то есть является в
некотором смысле аналогом Apache::PerlRun, поэтому мы его не
рассматриваем.
Модули FCGI, FCGI::ProcManager являются очень "зрелыми" и все
приведенные примеры предназначены для запуска FastCGI из-под
"пускалок", а не как самостоятельные, поэтому все примеры слегка
модифицируем. Перед основным циклом открываем сокет, который будет
слушать nignx:
use FCGI;
use CGI;
my $socket = FCGI::OpenSocket(":9000", 5); my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);
my $count = 0;
while($request->Accept() >= 0) {
$count++;
print <<TEXT;
Content-Type: text/html
<h1>hello</h1>
$count
<hr> TEXT
print "$_ = $ENV{$_}<br>\n" foreach sort keys %ENV;
print "<hr>\n";
my $query = CGI->new();
print "$_ = ", $query->param($_), "<br>\n" foreach sort $query->param();
}
FCGI::CloseSocket($socket);
Но это пример имеет большой недостаток: всего лишь один процесс
FastCGI. На помощь приходит модуль FCGI::ProcManager, который создает
до основного цикла заданное количество потомков, выполняющих всю
полезную работу по обработке запроса:
use FCGI;
use FCGI::ProcManager;
use CGI;
my $proc_manager = FCGI::ProcManager->new({ n_processes => 10 });
my $socket = FCGI::OpenSocket(":9000", 5);
my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);
$proc_manager->pm_manage();
my $count = 0; while($request->Accept() >= 0) { $count++; print <<TEXT; Content-Type: text/html
<h1>hello</h1>
$count
<hr> TEXT
print "$_ = $ENV{$_}<br>\n" foreach sort keys %ENV;
print "<hr>\n";
my $query = CGI->new();
print "$_ = ", $query->param($_), "<br>\n" foreach sort $query->param();
}
FCGI::CloseSocket($socket);
Кстати, если кто знает ответе: в линуксе до сих про плохо с большим
количеством прослушивающих один сокет процессов и проходится перед
аccept делать монопольную блокировку файла "регулировщика"?
Вернемся к основной теме. В примерах использования FCGI::ProcManager
используется модуль CGI::Fast, используя которых вышеприведенный
вариант можно привести к следующему виду:
BEGIN {
$ENV{FCGI_SOCKET_PATH} = ":9000";
$ENV{FCGI_LISTEN_QUEUE} = 5;
}
use CGI::Fast; use FCGI::ProcManager;
my $proc_manager = FCGI::ProcManager->new({ n_processes => 10 });
$proc_manager->pm_manage();
my $count = 0;
while(my $query = CGI::Fast->new()) {
$count++;
print <<TEXT;
Content-Type: text/html
<h1>hello</h1>
$count
<hr>
TEXT
print "$_ = $ENV{$_}<br>\n" foreach sort keys %ENV;
print "<hr>\n";
print "$_ = ", $query->param($_), "<br>\n" foreach sort $query->param(); }
Теперь рассмотрим фрейморки Catalyst и CGI::Application.
Для Catalyst создаем новый проект
catalyst.pl MyApp
и запускаем
myapp_fastcgi.pl -listen=localhost:9000 -nproc=10
Все просто. А вот с CGI::Application немного сложней. Модуль
CGI::Application::FastCGI, как оказалось, предназначен для работы
из-под "пускалки", поэтому используем не его, а непосредственно
FCGI::ProcManager.
BEGIN {
$ENV{FCGI_SOCKET_PATH} = ":9000";
$ENV{FCGI_LISTEN_QUEUE} = 5;
}
use WebApp;
use CGI::Fast;
use FCGI::ProcManager;
my $proc_manager = FCGI::ProcManager->new({ n_processes => 10 });
$proc_manager->pm_manage();
while(my $query = CGI::Fast->new()) {
my $app = WebApp->new(QUERY => $query);
$app->run();
}
Ну вот, с запуском разобрались, теперь посмотрим на использование
памяти в реальных условиях. Как и ожидалось выигрыша по памяти почти
нет, разумеется, когда Apache собран без излишеств.
Так что за nignx можно смело ставить либо mod_perl, либо FastCGI. Это
когда один скрипт. А когда скриптов несколько и они используют
множество общих модулей, то выигрыш варианта с mod_perl очевиден.
Ну вот пожалуй и все.
P.S. Если я где-то ошибся в рассуждения, просьба поправить.
<i>То есть люди массово избавлялись от Apache mod_php... Что это? Дань моде или нечто большее?</i>
Знаете отчего? Стас Бекман бросил проект, человек которому он его препоручил, philippe chiasson, тоже имеет его глубоко в виду, а люди которые в dev боятся как коммитить баги, так и развивать проект, абы чего не вышло. Поэтому mod_perl медленно но уверенно дохнет.