lighttpd + FastCGI は mod_perl + Apache1.3 より1割ほど高速

巷で超高速 Web サーバとして話題になっている lighttpd を試してみました。lighttpd に関する日本語ドキュメントは非常に少なく、ちょっと込み入った設定ファイルの記述方法とかの解析に手間取りました。

lighttpd のコンセプトは、「セキュアで省メモリで高速に動作し、柔軟性もある」なのですが、「lighttpd 公式サイトのベンチマーク結果」や「UnknownPlace. - Catalyst ベンチ」で簡単な Catalyst - Hello.cgi のベンチマークが公開されているとおり、Apache 1系、Apache 2系よりも高速に動作するようです。特に static なページの処理は Apache の 2〜3 倍程度は高速に処理できるみたいです。

また注目すべき点として、Apache + mod_perl よりも lighttpd + FastCGI の方が1割程度は高速と言う点です。

結果、lighttpd を導入することで、「リバースプロキシを導入する際はmod_rpaf」で紹介しているように、mod_perl を効率的に動作させる解としての「pound + Apache1-mod_perl + Apache2」や「Apache2-mod_proxy + Aapche1-mod_perl」なんて事が不要となり、lighttpd 1つでOKなんてことになります。

と言うことで、インストールして lighttpd に移行すべくいろいろ設定中なのですが、幾つかつまずいた点があるので備忘録です。

- スポンサーリンク -

FastCGI のインストール lighttpd で FastCGI を動作させるには、FastCGI 本体が必須です。

cd /usr/local/src
wget http://www.fastcgi.com/dist/fcgi.tar.gz
tar xvfz fcgi-2.4.0.tar.gz
cd fcgi-2.4.0
./configure
make
make check
make install

perl -MCPAN -e 'install FCGI'
perl -MCPAN -e 'install CGI::Fast'

libpcre (Perl Compatible Regular Expressions)のインストール lighttpd で mod_rewrite 等を動作させるには、libpcre (正規表現ライブラリ)が必須です。

cd /usr/local/src
wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-6.4.tar.gz
tar xvfz pcre-6.4.tar.gz
cd pcre-6.4
./configure
make
make install

PHP のインストール lighttpd で PHP を FastCGI として使う場合は、--enable-fastcgi オプションが必須。

cd /usr/local/src
wget http://jp.php.net/get/php-5.0.5.tar.gz/from/this/mirror
tar xvfz php-5.0.5.tar.gz
cd php-5.0.5
./configure \
--enable-fastcgi \
--enable-discard-path \
--enable-force-cgi-redirect \
--enable-mbstring \
--enable-mbregex \
--enable-mbstr-enc-trans \
--enable-iconv \
--enable-trans-sid \
--with-pgsql=/usr/local/pgsql \
--with-mysql=/usr/local/mysql \
--with-zlib=/usr --with-zlib-dir=/usr
make
make test
make install

cronolog のインストール ログをローテートするために必須です。

cd /usr/local/src
wget http://cronolog.org/download/cronolog-1.6.2.tar.gz
tar xvfz cronolog-1.6.2.tar.gz
cd cronolog-1.6.2
./configure
make
make install

lighttpd のインストール

cd /usr/local/src
wget http://www.lighttpd.net/download/lighttpd-1.4.4.tar.gz
tar xvfz lighttpd-1.4.4.tar.gz
cd lighttpd-1.4.4
./configure
make
make install
ln -s /usr/local/sbin/lighttpd /usr/sbin/lighttpd

以上で、lighttpd + FastCGI (perl) を使う下準備ができあがります。

次に、lighttpd の設定です。まず始めに lighttpd の自動起動と設定ファイルのテンプレートをコピーします。

cd /usr/local/src
cd lighttpd-1.4.4
cp doc/rc.lighttpd.redhat /etc/init.d/lighttpd
cp doc/lighttpd.conf /usr/local/etc/

/etc/init.d/lighttpd の設定 デフォルトの 起動ファイルを下記のように 25行目を変更します。

diff /usr/local/src/lighttpd-1.4.4/doc/rc.lighttpd.redhat /etc/init.d/lighttpd
25c25
%lt; LIGHTTPD_CONF_PATH="/etc/lighttpd/lighttpd.conf"
---
> LIGHTTPD_CONF_PATH="/usr/local/etc/lighttpd.conf"

/usr/local/etc/lighttpd.conf の設定 ココはご自分の Apache の httpd.conf を参考に設定します。httpd.conf とは記述方法がかなり異なるので、設定ファイルのドキュメントlighttpd の wiki を良く読みながら設定していきます。主立った設定ポイントとしては下記の通り。


server.modules
使いたいモジュールを指定する。モジュールの名前は Apache と同じなので理解はし易いですね。
server.modules              = (
"mod_rewrite",
"mod_access",
"mod_auth",
"mod_setenv",
"mod_fastcgi",
"mod_simple_vhost",
"mod_cgi",
"mod_accesslog" )

server.document-root
Apache で言うところの DocumentRoot です。
server.document-root        = "/usr/local/apache/htdocs/"

server.errorlog
Apache で言うところの ErrorLog です。エラーログのファイル名を指定します。
server.errorlog             = "/usr/local/apache/logs/error_log_L"

accesslog.filename
Apache で言うところの CustomLog です。アクセスログのファイル名を指定します。
accesslog.filename          = "/usr/local/apache/logs/access_log_L"

accesslog.format
Apache で言うところの LogFormat です。パラメータも互換があるので Apache の設定をそのまま使えます。
accesslog.format            = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""

index-file.names
Apache で言うところの DirectoryIndex です。ファイル名を指定しなかったときに、記述順にファイル名を補完してくれます。
index-file.names            = ( "index.html", "index.htm", "index.cgi", "index.php" )

mimetype.assign
Apache で言うところの TypesConfig です。必要な mime の設定を行います。
mimetype.assign             = (
".pdf" => "application/pdf",
〜中略〜
".tar.bz2" => "application/x-bzip-compressed-tar" )

server.port
Apache で言うところの Port です。通常 80 の指定で問題ないかと。
server.port                = 8003

server.username / server.groupname
Apache で言うところの User / Group です。lighttpd を動作させる user / group を指定します。
server.username            = "apache"
server.groupname = "apache"

cgi.assign
Apache で言うところの AddHandler cgi-script みたいなモノです。拡張子と対応するエンジンを指定します。
cgi.assign                 = ( ".pl"  => "/usr/bin/perl",
".cgi" => "/usr/bin/perl" )

server.error-handler-404
Apache で言うところの ErrorDocument 404 です。現時点では 404 以外のエラーに対して特別な html を指定することができないようです。
server.error-handler-404   = "/404.html"

auth.backend.htpasswd.userfile
Apache で言うところの .htpassword です。
auth.backend.htpasswd.userfile = "/usr/local/apache/htdocs/auth/.htpasswd"

auth.require
Apache で言うところの .htaccess に記述する認証設定です。記述方法が違うので戸惑うかも。
auth.require = ("/auth/" => (
"method" => "basic",
"realm" => "auth require pages",
"require" => "valid-user"
)
)

fastcgi.server
Apache で言うところの FastCgiConfig に相当するモノです。記述方法が違うので戸惑うかも。fastcgi.server の設定は通常 dispatcher cgi を指定します。従って、一般的な設定は下記の通りとなります。
fastcgi.server = ( ".fcgi" =>
(( "socket" => "/tmp/application.fcgi.socket",
"bin-path" => "/usr/local/apache/scripts/dispatch.fcgi",
"min-procs" => 10,
"max-procs" => 20,
"idle-timeout" => 20
))
)
dispatch.fcgi のソースは例えばこんな感じのモノを参考に wiki にあります。
#!/usr/bin/perl
use strict;
use CGI::Fast;
use Embed::Persistent;
{
my $p = Embed::Persistent->new();
while (new CGI::Fast) {
my $filename = $ENV{SCRIPT_FILENAME};
my $package = $p->valid_package_name($filename);
my $mtime;
if ($p->cached($filename, $package, \$mtime)) {
eval {$package->handler;};
} else {
$p->eval_file($ENV{SCRIPT_FILENAME});
}
}
}

ただ、これだと特定の FastCGI プロセス数を管理できないので、下記のように個別に設定すると良い感じ。

fastcgi.server = (
"/test1.fcgi" => (
"test1" => (
"socket" => "/tmp/fastcgi_test1.socket",
"bin-path" => "/usr/local/apache/scripts/test1.fcgi",
"min-procs" => 1,
"max-procs" => 1,
"idle-timeout" => 20
)
),
"/test2.fcgi" => (
"test2" => (
"socket" => "/tmp/fastcgi_test2.socket",
"bin-path" => "/usr/local/apache/scripts/test2.fcgi",
"min-procs" => 2,
"max-procs" => 3,
"idle-timeout" => 20
)
)
)

$HTTP["host"]
Apache で言うところの VirtualHost に相当するモノです。全てのパラメータは VirtualHost 毎に個別に設定可能です。
$HTTP["host"] == "www.drk7.jp" {
server.document-root= "/home/apache/drk7.jp"
server.name = "www.drk7.jp"
accesslog.format = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
accesslog.filename = "|/usr/local/sbin/cronolog /home/apache/drk7.jp/logs/access_log_L.%Y%m%d"
server.errorlog = "/home/apache/drk7.jp/logs/error_log_L"}

最後に簡単な CGI でベンチマークを図ってみました。ウワサ通り、mod_perl より1割程度高速な結果が出ました。

mod_perl サンプル CGI のソース

#!/usr/bin/perl

use strict;
use CGI;
our %count;

&_process_request(CGI->new);

sub _process_request() {
my $q = shift;
my $procid = $q->param('pid');
$count{$procid} += 1;

print $q->header( -type=>'text/html',-charset=>'EUC-JP' );
print qq{
FastCGI Hello! (Perl)

FastCGI Hello! (Perl)


ProcID : $$ : $procid

Request number : $count{$procid}

};
}

FastCGI サンプル CGI のソース

#!/usr/bin/perl

use strict;
use CGI::Fast;
our %count;

while (my $q = CGI::Fast->new) {
&_process_request($q);
}

sub _process_request() {
my $q = shift;
my $procid = $q->param('pid');
$count{$procid} += 1;

print $q->header( -type=>'text/html',-charset=>'EUC-JP' );
print qq{
FastCGI Hello! (Perl)

FastCGI Hello! (Perl)


ProcID : $$ : $procid

Request number : $count{$procid}

};
}

ベンチマーク結果

/usr/local/apache/bin/ab -n 100 -c 10 http://localhost/test1.cgi
Requests per second: 740.74 [#/sec] (mean)
Time per request: 13.50 [ms] (mean)
Time per request: 1.35 [ms] (mean, across all concurrent requests)
Transfer rate: 217.52 [Kbytes/sec] received

/usr/local/apache/bin/ab -n 100 -c 10 http://localhost/test1.fcgi
Requests per second: 862.07 [#/sec] (mean)
Time per request: 11.60 [ms] (mean)
Time per request: 1.16 [ms] (mean, across all concurrent requests)
Transfer rate: 246.48 [Kbytes/sec] received

さぁ、興味がわいた方は Apache から lighttpd へ移行してみよう!

- スポンサーリンク -