先週のエントリーで、mod_perlはポート待ち受けする全てのhttpdの内部にperlを常駐させるのでメモリを使いまくって困る、と書いたが、当然その課題については色々考えられてきたようで、mod_perlの様々な文書に対策が書かれていることがわかった。
最初に見つけたのは、単純にもman mod_perlの中だった。"MEMORY CONSUMPTION"という章があり、メモリ消費量が増える理由や、Perlスクリプトを書く時のノウハウが書かれている。さらにman mod_perl_tuningにずばり"REDUCING MEMORY USE"という章があり、次のような方法が紹介されている。
(1) httpdのプロセス数を減らす
(2) httpdが子プロセスをforkする前にPerlモジュールをできるだけ事前にロードして子プロセス間のRAMの共有化を図る(OSによってはあるメモリ領域に書き込みが発生するまではそのメモリ領域のコピーを子プロセスに作らないため)
(3) 通常のコンテンツ用のhttpd(多数の接続を許す)とmod_perlするhttpd(少数の接続のみ)とを分ける
mod_perlのサイトのDocumentationの"Choosing the Right Strategy"や"Performance Tuning"の所にも色々な情報があるが、大まかには上記の3通りの方法にまとめられると思う。
このWeblogを動かしているサーバーに関しては、(1)はhttpd.confのMaxSpareServersもMaxClientsも最少限にしてあるので無理、(2)は前回の設定で半分程度はなされており、これ以上はMovableTypeに手を加えることを意味し大変なので、(3)のように2種類のhttpdを動かす選択が妥当だ。
そして、複数のhttpdをシームレスに動かすと言えば、Apacheのmod_proxyだ。httpdに届いたHTTPリクエストを他のHTTPサーバーに転送できる機能だ。Apacheを使っていてHTTPサーバーの連携にmod_proxyを使わない手は無い。
ところで、このサーバーにはApacheとTomcatとが動いていて、それぞれ待ち受けポート番号が異なり、2つのポートをインターネットに公開しないといけないことと、一方のコンテンツのURLにポート番号が含まれるのが気になっていた。先々週、Apacheのmod_proxyのことを知り、それを使えば解決することがわかったので、mod_perlを組み込むのと同時に、mod_proxyを使えるようにApache 1.3を再コンパイルしていた。
そのmod_proxyを使って、mod_perlを外したApacheのhttpdとmod_perlを組み込んだApacheのhttpdを繋げれば良いのだ。実に幸便、渡りに船だ。
今回mod_proxyを使って作成した環境を大まかに説明する。
HTTPサーバーは上述のように3つの構成(同一PCで動く)とした。
(A) mod_proxyを組み込んだApacheのhttpd
(B) mod_perlを組み込んだApacheのhttpd
(C) Tomcat
インターネットからのHTTPリクエストは全て(A)が受け取り、リクエストのURLを見て、Perlを起動するべきコンテンツであればリクエストを(B)に転送し、Tomcatの管轄のコンテンツであればリクエストを(C)に転送する。
●mod_proxyの設定
特に細かいことをしなければ、mod_proxyの設定は至って簡単だ。
今回は、上記(A)のhttpd.confに以下を追加した。ここでは(B)はポート81、(C)はポート8080で待ち受けているとする。
ProxyPass /mt/ http://localhost:81/mt/言うまでも無く上4行が(B)への転送、下2行が(C)への転送の設定だ。
ProxyPassReverse /mt/ http://localhost:81/mt/
ProxyPass /cgi-bin/mt/ http://localhost:81/cgi-bin/mt/
ProxyPassReverse /cgi-bin/mt/ http://localhost:81/cgi-bin/mt/
ProxyPass /cgi-bin/mt/mt/app http://localhost:81/mt/app
ProxyPass /cgi-bin/mt/mt-search.cgi http://localhost:81/mt/search
ProxyPass /servlet/ http://localhost:8080/servlet/
ProxyPassReverse /servlet/ http://localhost:8080/servlet/
(10/29訂正:取り消し線部分2行削除、その下に2行追加)
●httpd二重化の設定
2種類のhttpdを動作させるために、通常、最低
・httpd.conf
・ロックファイル、PIDファイル
・起動スクリプト(/etc/rcまたはそこから呼ばれるもの)
を別々にする必要があると思われる。
httpd.confは、異なるファイル名で2つ用意し、httpdの起動時に"-f"オプションを指定して区別させれば良い。
ロックファイルやPIDファイルの指定は、httpd.confの中で行う。それぞれ"LockFile"、"PidFile"の行で別々のものを設定する。
今回、最終的に(A)と(B)のhttpd.confの差分は次のものとなった。
・LockFile/PidFileの設定
・ErrorLogの設定
・ポート番号
・httpdプロセスの数に関係する値(MaxSpareServers, MinSpareServers, StartServers, MaxClients)
・mod_proxyの設定
・mod_perlの設定(LoadModuleやAddModuleも含めて)
起動スクリプトについては、本サーバーはFreeBSD 4.xなので、それに特化した話になるが、/usr/local/etc/rc.d/にapache-backend.shというファイルを追加した。apache.shとの差分は次の通り。
・apache_flagsの行("-f (config)"によるhttpd.confの指定)
・apache_pidfileの行(httpd.confのPidFileと同じものにする。httpdを通さない処理に必要になる)
ynomura
上記のmod_proxyの設定で、MovableTypeの全てのCGIへの要求をmod_perlサーバーに転送するようにしていたが、それだとMovableType的にまずいことがわかった。
コメントのCGI(mt-comments.cgi)への要求がproxyされると、コメントの送信元IPアドレスが全てlocalhostになってしまい、IPアドレスによる迷惑コメントのフィルタリングが効かなくなり、さらにMovableTypeによってlocalhostが勝手に「禁止IP」に追加されてしまい、一切のコメントが投稿できなくなってしまうのだ。
従って、mod_perlで処理されるCGI要求だけをmod_perlサーバーにproxyするように設定を変更した。
同様の理由で、このサーバーではコメントのCGIをmod_perl化できないことが確定した。