最近、「MovableType は Perl で書かれてるから重い」てな発言を時々目にしたりしますが、それが「PHP や Java で書かれたウェブアプリケーションと比べて」という話であった場合には、川合孝典さんの書いた 'PerlよりPHPの方が軽くて速いは本当?' や 'JavaはPerlよりも比較にならないほど速い?' を読んでみろと小一時間問い詰めたくなります。
確かにごくごく標準的な環境下で CGI プログラムとして MovableType (のCGI)を動作させた場合、結構な負荷になると思います。一部のホスティング業者では夜間の負荷制限に引っかかってしまって rebuild に失敗したりするという話も聞いていますし。
しかしそれはあくまで標準的な環境でのお話。mod_perl 環境下で動かすとその体感速度は劇的に向上します。正直、mod_perl じゃない環境へはもう戻れません。PHP や Java で書かれた blog ツールなどと速度比較する場合には、川合さんの文書にもあるように、この環境と比較することも検討して欲しいと思う今日この頃。
というわけで、mod_perl (Apache::Registry) 環境下で MovableType を動作させる方法をちょろっとまとめておきます。実践できる環境は一部に限られてしまいますが、興味のある方は是非お試し下さい。
まずは mod_perl が動作する環境の整備から。Apache と mod_perl をサーバにインストールします。ここでは Apache はバージョン 1.3 系を、mod_perl は 1.X 系を使います。Apache は 2.0 系でもあまり大差ないと思いますが、 mod_perl の 2.0 系は開発版なので、1.X 系が良いでしょう。今回は、
Downloading Apache から apache_1.3.28.tar.gz
mod_perl: Download から mod_perl-1.0-current.tar.gz
をダウンロードしました。
まずは Apache のコンパイルとインストール。mod_perl をインストールする場合、方法は二つあり、ひとつは直接 Apache に静的に組み込む方法、もう一つは Apache DSO を利用して、Apache のコアとは分離させて組み込む方法。ここでは汎用性の高い後者を採用します。そのため Apache をコンパイルする際、DSO サポートを有効にします。
$ tar zxvf apache_1.3.28.tar.gz $ cd apache_1.3.28 $ CFLAGS=-O2 ./configure \ > --enable-rule=SHARED_CORE \ > --enable-module=all \ > --enable-shared=max $ make $ su Password: # make install
これで /usr/local/apache に Apache がインストールされます。パスを他にしたい人は、
$ ./configure --prefix=/usr/local/apachce_test \ (以下同じ)
などとすれば良いでしょう。
次に mod_perl のコンパイルとインストール。USE_APXS=1 オプションを有効にすることで、mod_perl が DSO としてビルドされます。このとき、先にインストールした Apache に含まれる apxs という実行ファイルが必要になります。apxs のパスを WITH_APXS オプションで指定します。その他のオプションにはすべて yes で答えるということで、EVERYTHING=1 オプションも付けます。
# exit $ cd .. $ tar zxvf mod_perl-1.0-gurrent.tar.gz $ cd mod_perl-1.28 $ perl Makefile.PL \ > USE_APXS=1 \ > WITH_APXS=/usr/local/apache/bin/apxs \ > EVERYTHING=1 $ make $ su Password: # make install
これで完了です。(以降、Apache のインストールディレクトリを $APACHE_HOME とします。)
$APACHE_HOME/libexec の中に、libperl.so というファイルがあると思います。これが DSO でビルドされた mod_perl の本体になります。
試しに Apache を動かしてみましょう。デフォルトの設定では Port 8080 になってるかと思います。試験的に動かすだけなので、そのままで。
# cd $APACHE_HOME/bin # ./apachectl start ./apachectl start: httpd started
http://(サーバのホスト名またはアドレス):8080/ にアクセスして Apache のデフォルト画面が表示されたら OK です。
次に mod_perl の動作を確認します。mod_perl に標準で付属している Apache::Status モジュールを利用すると、mod_perl に関する様々なステータスやデバッグ情報をブラウザに出力させることができます。試しに Apache::Status を動かしてみて mod_perl の動作確認とします。(『Apache 拡張ガイド』には、CPAN の Devel::Symdump モジュールが必要だとありますが、僕の環境ではそれなしで動きました。万が一動作しない場合は CPAN から Devel::Symdump や Data::Dumper あたりをインストールしてみてください。)
Apache::Status を利用するには $APACHE_HOME/conf/httpd.conf に以下の記述を追加します。追加する場所は、<Directory "..."> といったディレクテブが記述されてる近辺がいいかと思います。(もちろん、<Directory "..."> 〜 </Directory> の中に書いてはいけません。)
<Location /perl-status> SetHandler perl-script PerlHandler Apache::Status </Location>
Apache を再起動して設定を読み込ませます。
# cd $APACHE_HOME/bin # ./apachectl graceful ./apachectl graceful: httpd gracefully restarted
http://(サーバのホスト名またはアドレス):8080/perl-status/ にアクセスして Apache::Status の出力が得られれば OK です。ちなみに、この Apache::Status の "Loaded Modules" メニューでは、そのとき mod_perl が読み出しているモジュールの一覧を見ることができますが、MovableType を mod_perl で動かした際には MT モジュール関連が読み出されていることが確認できますので、動作確認に使えます。(それ以外にも "Inheritance Tree" ではクラスの継承マップがツリー表示されるので、MovableType のコード解析にも役立ったりします。)
さて、次は MovableType のインストール。ここは割愛します。/path/to/mt にインストールしたこととします。MovableType の動作確認しようと思ったけど CGI が動かねーよ!! ってな方は Google で "AddHandler cgi-script ExecCGI" とか検索すれば良いかと思います。
あと、docs、images、style.css は mt.cgi は別のディレクトリに切り分けた方が無難かもしれません。(see '困った時には')
さて、いよいよ mod_perl で MovableType の実行を高速化します。
(以下、うんちく。読み飛ばしていただいて結構)
そもそも mod_perl を使うと何で速くなるのかという話ですが、簡単に言うと、Perlインタプリタをサーバに組み込むことによって Perl コードから Apache API に直接アクセスすることを可能とし、Perl の起動によるオーバーヘッドやCGI実行時の子プロセス生成のオーバーヘッドをカットすることで 200% 〜 2000% の高速化が可能となる、という仕組みです。
通常、CGI プログラムはその実行が完了すると、そこで役目を終えてその動作を終了しますが、mod_perl で動作する Perl コードは初回の実行時にメモリ上にキャッシュされ、以降のアクセスはそのメモリに常駐したプログラムが処理することになります。単に Perl 起動時のオーバーヘッドなどが回避されるだけでなく、メモリに常駐することでデータベースへの接続を永続化(コネクションプーリング)したりすることも可能になります。
(うんちく終わり)
mod_perl を使って CGI プログラムを動かすには、(mod_perl に標準で含まれる) Apache::Registry や Apache::PerlRun といったモジュールを使って CGI 環境エミュレートを行い、その下で動作させます。これらのモジュールは先に説明した Perl コードのメモリ常駐化などを一手に担ってくれます。ただし、Perl スクリプトに含まれるグローバル変数などの取り扱いに注意が必要になり、Apache::PerlRun よりも Apache::Registry の方がその辺りの制限に対して厳くなっています。その分、Apache::Registry の方がより高速です。MovableType のコードは Apache::Registry によって動作させることが可能になっています。
MovableType を Apache::Registry 環境下で動かすためには mod_perl には含まれない Apache::Request と Apache::Cookie のインストールが必要になります。(これらのモジュールは libapreq 配布に含まれています。) CPAN 経由でインストールできます。
# perl -MCPAN -e shell cpan> install Apache::Request
僕がインストールしたときは、make test で失敗しましたが、無理やりインストールしました。force install Apache::Request とするなり、~/.cpan/build に展開されたディレクトリで make install するなりで OK だと思います。(ほんとにそれでいいのかしら。)
次に、$APACHE_HOME/conf/httpd.conf に以下を追加します。(/path/to/mt は MovableType をインストールしたディレクトリに適時読み替えてください。)
PerlSetEnv PERL5LIB /path/to/mt/lib:/path/to/mt/extlib PerlModule Apache::Registry <Directory "/path/to/mt"> SetHandler perl-script PerlHandler Apache::Registry # PerlModule Apache::DBI Options +ExecCGI PerlSendHeader Off </Directory>
MovableType のマニュアルには PerlSetEnv の行は含まれていないのですが、僕の環境ではこれが無いと動きませんでした。データベースに MySQL や PostgreSQL などを使っている場合は、PerlModule Apache::DBI のところをコメントアウトするとコネクションプーリングが有効になり、更に幸せになれます。(なれるはず。ほんとにちゃんとできてるか調べてない。)
書き加えたら Apache を再起動して、mt.cgi にアクセスしてみてください。
# cd $APACHE_HOME/bin # apachectl graceful ./apachectl graceful: httpd gracefully restarted
mod_perl の性質上、初回起動時はそんなに速くないかもしれませんが、二度目以降のアクセスは劇的に速くなっているかと思います。
長くなったし以上、と言いたいところですが、コードを一箇所だけ修正する必要があります。BookMarklet を使おうとすると "Undefined subroutine &CGI::unescape called at /usr/local/apache/htdocs/app/mt/lib/MT/App/CMS.pm line 639. " とか言われてしまうので、/path/to/mt/lib/MT/App/CMS.pm で use Jcode; とかしているところで
use Jcode; use CGI; use Symbol; ...
と use CGI の一文を加えてください。
以上、mod_perl 環境下で動作させるための方法をざーっと書きましたが、ウェブサーバーの細かい設定なんかは全く書いてないので、公開する場合はその辺怠り無く。
ちなみに(まだちなむのか)、MovableType のマニュアルには更に高速化させる方法として mod_perl ハンドラとして動作させる方法も載ってます。
遅れ馳せながら、わたしもやってみました。管理画面のきりかわりがサクサクしていいですね。わたしは、おとなしく(?) mt のマニュアル通りにやりました。普段、apache2 を使っているので、1.3 も立ち上げたりしましたが。メモリもCPUもプアなうちのマシンでは負荷が大きいような気がするので、今後も使うか考え中...。
Apache::Request のインストールでテストがうごかないのは、コンパイル時に apache のヘッダファイルの include に失敗いるからでは? うちではpathを直してインストールしました。(libapreq)/c/apache_request.h の #include "httpd.h" から始まるブロックです。
Rebuild 自体は Berkeley DB を使っていると、あんまり早くならないような気がしました。mysql にして、DB を別マシンに移すと早くなった気がします。150エントリーで、40秒かかっていたものが、30秒になった、ってところです。このへんは、Perl とかよりも、もう三年も頑張っているうちの非力なマシンとディスクの問題のような気がします。
ちなみに、TrackBack の use CGI; って追加しなくても動くような気がするんですが、どういうときに起きる問題だったんでしょうか? あと、PerlSetEnv は最初の <Perl> のところで指定しているので、それで書かれていないのだとおもいます。
どうもです。
libapreq の make test のエラーは、その後調べたところ、Apache の apxs が原因でした。僕の環境では RPM から入れた Apache とソースから作った Apache が混在していて、mod_perl を後者に合わせて作ったにも関わらず前者に付属する apxs を読みにいってしまって、テストできねーよってエラーでした。
環境変数 PATH に後者の Apache の bin のパスを入れて解決しました。
use CGI の件は、みらのさんの日本語化パッチを当てた場合に Bookmarklet で CGI::unescape が使われていて、そいつを取り込めずに undefined subroutine になってましたので、use CGI を加えてます。
今のパッチでは直ってるかもしれません。
> Bookmarklet で CGI::unescape
意味わかんないですね。w
Bookmarklet のコードのところで CGI::unescape、が正しいか。
[3] Posted by: naoya at September 13, 2003 07:00 PM [返信]