mod_perl 2.0 での2種類のハンドラ modperl と perl-script

mod_perl 2.0 では,SetHandler で指定するハンドラタイプとして,modperl と perl-script の2種類があります。この違いは何なんだろうと思い,mod_perl のドキュメント を読み込んでみました。

おおざっぱにまとめると,一般的に使うべきなのは perl-script タイプで,mod_perl のヘルパが便利なようにいろいろ設定してくれてます。たとえば,

  • $ENV{QUERY_STRING} や $ENV{REMOTE_ADDR} 等の環境変数を設定してくれている
  • STDOUT や STDIN を読み書きすることで,CGI としての入出力ができるようにしてくれている

などですね。
ですから,

  • $ENV{REMOTE_ADDR} 等は,$r->connection()->remote_host() 等使って自力で取得するし
  • 出力も $r->print() 等使うからいいや

みたく自力でがんばっていてパフォーマンスを重視するハンドラの場合 modperl タイプも選択肢に入ってくると思います(パフォーマンスは気にならないほどの違いだとは思いますが)。また,よりコアに近いモジュールを開発していて perl-script タイプのハンドラで提供されるサービスが余計なお世話だ,と思うときも,modperl タイプが向いていると思います。

結論としては,普通にウェブアプリを開発する場合,perl-script という設定で十分ということです。一応,mod_perl 2.0 のドキュメントの該当部分の意訳を以下に載せておきます。

抄訳

modperl ハンドラタイプ

生の mod_perl ハンドラタイプであり,Perl*Handler コールバック関数を呼ぶことしかしません。perl-script ハンドラの提供する特長が必要ないなら,modperl ハンドラを使うほうがよりよい性能を得ることができます。
(このハンドラは mod_perl 1.0 では使えません)

modperl タイプのハンドラで,ごにょごにょ(*)していない場合,
下記の環境変数しか取得できません。

(*) 「ごにょごにょ」ですが,
設定ファイルに

PerlOptions +SetupEnv

という設定をしておくか,もしくは,ハンドラの中で,空コンテキストで引数のない

$r->subprocess_env;

を呼び出すことにより,その他の環境変数を %ENV に構築することができます。

ですから,単になにがしかの設定値を httpd.conf から取得したい場合,%ENV を構築するオーバーヘッドがいやなら,PerlSetEnv や PerlPassEnv の代わりに PerlSetVar や PerlAddVar を使うことを考慮に入れてみてください。これらの値は dir_config() 関数で取得できます。
たとえば httpd.conf で

<Location /print_env2>
    SetHandler modperl
    PerlResponseHandler Apache2::VarTest
    PerlSetVar VarTest VarTestValue
</Location>

と設定してある場合,この値は,Apache2::VarTest::handler() の中で,

$r->dir_config('VarTest');

として取得できます。

この方法の代わりに,Apache コアディレクティブの SetEnv や PassEnv を使うこともできます。これを使うと常に $r->subprocess_env() が呼び出されます。ですが,Apache の fixups フェイズまで呼び出されません。これはタイミングが遅すぎるかもしれませんね。

また,modperl タイプのハンドラは,各リクエストのレスポンスフェイズの後に %ENV をリセットしないことにも注意が必要です。ですから,あるレスポンスハンドラがローカライズすることなく %ENV を変更した場合,他のハンドラにも変更した影響が現れることでしょう。

perl-script ハンドラタイプ

ほとんどの mod_perl ハンドラでは perl-script ハンドラが使われています。特に注目するべき挙動としては,

  1. 明示的に「PerlOptions -GlobalRequest」としていない限り,PerlResponceHandler フェイズでは PerlOptions +GlobalRequest が有効となっています。
  2. 明示的に「PerlOptions -SetupEnv」としていない限り,PerlOptions +SetupEnv が有効になっています。
  3. STDIN と STDOUT がリクエストオブジェクト $r に tie されています。ですから,$r->puts() とか明示的に呼び出さなくても,STDIN からリクエストを読み取ったり,STDOUT に CORE::print() を使ってレスポンスを出力したりできます。
  4. いくつかの特別な Perlグローバル変数は,レスポンスハンドラの呼び出しをまたいで保存されます。これは mod_perl 1.0 と同じような挙動です。具体的には,%ENV, @INC, $/, STDOUT の $|, そして END ブロックの配列(PL_endav)です。
  5. %ENV に追加されたエンティティは,subprocess_env テーブルに複製されます。ですから,PerlLogHandler フェイズや PerlCleanupHandler フェイズで $r->subprocess_env によってそれらを取得可能です。