複数のテストサーバをリバースプロキシで集約 (3)
複数のテストサーバをリバースプロキシで集約 (1) - daily dayflower と 複数のテストサーバをリバースプロキシで集約 (2) - daily dayflower の続きです。
mod_rewrite の RewriteMap を使ってごにょごにょしましたが,なんともまどろっこしかったです。そもそも URI の書き換えに癖のある DSL を使う mod_rewrite を使わなきゃいけないということ自体がアレです。もっと手になじんだプログラミング言語で書ければロジックもすっきりするのに!
というわけでモジュールを書いてみました(mod_proxy_mapper.c - daily dayflower)。
プロキシ専用ですが,サブリクエストを使ってプロキシ先を選定するモジュールです。
- サブリクエストを使っているので,Apache でサポートしている言語ハンドラ……CGI*1 なり PHP*2 なり mod_perl((mod_perl 使うならこんなの使わずそもそも自分で
PerlFixupHandler
書くべきでしょう。)) なりを使ってかける - リクエストのたびにサブリクエストを発行するのでパフォーマンスゲインは相当のもの
なんて toy module ですが,まぁ後者は(プロダクション環境でなければ)そんなに気になるほどのことでもないです。
2008-11-18 追記
cons を強調して書いたので一応 pros も書いておくと,
- 自由自在なアルゴリズムでプロキシ先を決定できる
- たとえばアクセスした日時によりプロキシ先を決定したり,アクセス元 IP address にしたがってプロキシ先を決定したり
2008-11-18 追記おわり
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule proxy_mapper_module modules/mod_proxy_mapper.so ProxyMapper file:///var/www/main/proxymap/mapper.cgi <Directory /var/www/main/proxymap/> Options ExecCGI AddHandler cgi-script cgi # AddHandler persitentperl-script cgi Order allow,deny Allow from all ProxyMapper none </Directory>
のように設定します。
ProxyMapper
という設定子でプロキシマッピングのためのファイルパス/URI パスを指定します。URI パスも指定できますが,サブリクエストなので外部サーバに投げることはできません。ので Fully Qualified URI ではなくパスを指定してください。そもそもモジュールの性質上,ファイルパス(file://
を先頭に書くとファイルパスとみなします)を指定したほうがよいです。
またトップで ProxyMapper
を指定していますが,一応 <Location>
や .htaccess
レベルでも設定できます。が,やはり性格上,トップで指定することになるでしょう。
mapper.cgi
の例です。
#!/usr/bin/perl use strict; use warnings; our $CONFIG = <<'END_YAML'; --- outer1.example.com: /path1: http://inner-a.example.com/path1 /path2: http://inner-b.example.com/path2 /: NULL outer2.example.com: /path3: http://inner-b.example.com/path3 /: NULL END_YAML use YAML; my $server = $ENV{HTTP_HOST}; my $path = $ENV{REQUEST_URI}; #my $mapping = YAML::LoadFile('proxy.yaml'); my $mapping = YAML::Load($CONFIG); my $result; if (exists $mapping->{$server}) { my $len = 0; foreach my $key (%{$mapping->{$server}}) { next if $len > length $key; if (substr($path, 0, length $key) eq $key) { $result = $mapping->{$server}->{$key}; $result .= substr $path, length $key; $len = length $key; } } } if (defined $result) { print "Location: ${result}\n\n"; } else { print "Status: 404 Not Found\n\n"; }
Location
ヘッダに Fully Qualified URI を指定すると mod_proxy に移譲します。ステータスコードを 404 にすると,元のリクエストのステータスコードも 404 になります。