こんにちは、先日YAPCトークデビューした おがた (@xtetsuji) です。
YAPC::Asia Tokyo 2012 に行ってきた感想については以前のエントリでたっぷり書いたので、ここでは、YAPCで初トークした「モダンmod_perl入門」の詳細や、これにいたる経緯、そしてこれからの計画について書いてみようと思います。
トークのフォロー
まずはトークを聴講しにきてくださった方々、ありがとうございます。
話したい事がいっぱいあって、20分の枠に収めるのにトーク直前まで四苦八苦していたのですが、時間超過などのカッコ悪いことにならず、何とかうまく話せたかなと自分では思っています。
トーク内容の一部フォロー
SlideShareにアップロードする段階でトークのスライドを見返していて、ちょっと説明不足だったかなというところがあったので、ここで補足させていただきます。
mod_rewriteのPerlTransHandlerでのリファクタリングの話で、「Directory Contextに書かれたmod_rewriteの場合、別途ケアが必要になる場合がある」といった内容に触れました。Directory Context の例として <Location> と .htaccess をスライドで例示していますが、まさに Directory Context の代表と言える <Directory> に触れていないのは、単に忘れていただけです。
実際、mod_rewriteは「URLを書き換える」処理を行っているわけですが、PerlTransHandlerに対応するApacheフェーズでは、まだURLから実ディレクトリへのマッピング処理が完了していません。Apache設定のルートや<VirtualHost>直下に書かれたmod_rewriteの場合は、まだURLから実ディレクトリへのマッピング処理が行われない段階、つまりPerlTransHandlerと同じフェーズで処理されるので問題がないのですが、Directory Contextでは既にURLから実ディレクトリの解決が済んでいるわけです。mod_rewriteは、この部分をうまく解決するために内部的に多少面倒な事を行っています。このようなこともあり、mod_rewrite では $r (Apacheモジュールでいえば request_rec 構造体 r) が持っている uri 情報を実際は書き換えず、書き換えて穏当に実ディレクトリを解決したように見せかける処理を PerlFixupHandler と同等の場所(リクエスト処理フェーズの直前)で行っています。通常は問題にならないと思いますが、レスポンスフェーズで動作するプログラム(CGI, PHP, mod_perl Registryスクリプト等)がURLをつぶさに見る場合に状況によっては mod_rewrite → mod_perl PerlTransHandler の単純な書き換えで同等の動作が保証されない場合もあります。この辺りは mod_rewrite が見事とも言える複雑な処理をしている部分が大きいです。皮肉ですが、mod_rewrite 設定がすぐに魔窟になる所以でもあるでしょう。
PHPとの連携については、PHP以外の言語でもレスポンスフェーズで入出力を処理するものについては同様の事ができるはずですが、自信がなかったので私が経験したPHPとの連携に限ったお話とさせていただきました。PHPがレスポンスフェーズ以外でほとんど仕事をしないポリシーであることはPHPのコア開発者が述べていることでもあります(これはApache以外へのPHPの移植性を考えてのことでしょう)。その明瞭さゆえ、レスポンスフェーズでPHPが動作する場合、他のフェーズでmod_perlを投入することで干渉が起こらないと言っていいのです。
最近はdisられ役になったり、PHPプログラマ自身がそれを自嘲気味にネタにする時代ですが、私はPHPが得意な人・Perlが得意な人で協力しながら開発をする姿も良いと思っていますし、mod_perlがPHPとPerlを繋ぐ糊(glue)となって欲しいという思いもあります。誤解は無いとは思っていますが、少なくとも私のトークではPHPをdisったりする意図はありません。だからといって、多種多彩なプログラム言語で書かれたプログラムが乱立している状況だと保守性もへったくれもないので、必要性に応じて仕事では社内のプログラム言語はある程度統一しておいたほうがいいかなとは思います。
ただ…、過去にPHPで絡ませて頂いた仕事の半分くらいは痛い目に会っているんですよね。これは私が、スキルの低いPHP開発者とたまたま一緒に仕事をせざるを得なかっただけの話かもしれませんが…。しかしそのおかげで、PHPの勉強をサボろうという猛烈な熱意がmod_perl力をさらに向上させたとも言えるでしょう。もちろん、気持よく一緒に仕事をさせていただいたPHPプログラマの方も多くいらっしゃって、勉強させていただいたことも多くありました。その節は本当に助かったと同時に、良質なコードからPHPの勉強も自然とさせていただきました。
認証・許可処理は名前通り PerlAuthenHnadler・PerlAuthzHandler に書くべきでしたが、例示したコンセプト(スケルトン)ハンドラは PerlAccessHandler での設定でした。これには言い訳があって、Authen/Authzは癖があってApacheコアのRequireディレクティブなどと組み合わせないといけないのが面倒だっただけです。本来、PerlAccessHandlerはアクセス制御処理(IPアドレスでのアクセス制限等)を入れるフェーズですが、認証・許可処理を手軽にやるときはPerlAccessHandlerに書いてしまえというのは単なる私の怠け癖です。実際、アクセス制御処理を行う場合、単純なIPアドレス処理のようにヘッダを見ないのであれば、遥か前 PerlHeaderParserHandler のさらに以前である PerlPostReadRequestHandler でやってしまったほうが効率的なのです(多くの処理フェーズを省けるわけですから)。
Perlのスレッド(ithreads)をApacheのworker MPMと合わせて使うことでprefork MPMでは実現できない変数共有といったお話もしました。ただ、スライドでworker MPMはスレッドとプロセスのハイブリッドであると言っているのに変数共有できるのはなぜ?という疑問が湧いた方もいらっしゃったかと思います。これは完全に設定の説明を失念していて、worker MPMで生成されるプロセスを1つにするという設定が必要です(1プロセス・マルチスレッドの状態にする)。詳しい説明はここでは割愛しますが、ざっくりと StartServers、ServerLimit、PerlInterpStart、PerlInterpMax の各ディレクティブの設定値を 1 にしておけば良いはずです。スレッド設定については、MinSpareThreads、MaxSpareThreads、ThreadsPerChild の各種設定値を用途と環境によって適宜調整下さい。
ただ、トークでも何度も繰り返していましたが、現状Perlのスレッド(ithreads)は決して使用をすすめられるものではありません。諸事情あって私はこれを商用環境に投入することになりましたが、原則的に勧められることでは無いと思います。ただ、prefork MPM 以外、worker MPMがあまり陽の目を見ないことと、mod_perlの一つの可能性を知っていただきたかったので、今回トークのネタにしました。
他のmod_{lang}との比較をしようとは以前から考えていたのですが、検索すればあらゆるプログラム言語のmod_{lang}が出てくる状態はカオスでした。もちろん「コンセプトで実装してみました」で後は放置されて実用段階に無いものがほとんどなのですが、mod_ruby や mod_python についてはその名前から今も現役(現在のmod_perlと同等の実用性を持ち、保守がなされている)と誤解している方がまだいるのではないかと思ったので、念押しで解説させていただきました。
mod_ruby は、まだRails以前のRubyのエコシステムがそれほど整備されていなかった当時、Perlに追いつけと主にRegistryスクリプトに対応するものができるようにと mod_perl (mod_perl1) と対応したものを作ったものと私は理解しています。mod_ruby は Apache2 には少なくとも正式には対応されていないはずです。Rails以後は、Lighttpd + FastCGI が定石になって、その後 Rack 方面へと進んだと私は理解しています。
Apacheを拡張するものとしての mod_perl (mod_perl2) に対応するものは、現時点では mod_mruby でしょう。組み込み用途の mruby が今年2012年4月に登場してすぐに登場した mod_mruby ですが、現在も作者の @matsumotory さん (まつもとりょうすけさん) によって精力的に開発が進められています。「ApacheをC以外の他の言語で拡張する」という用途がmod_mrubyで見直され、それがmod_perlの「再発見」にもつながってほしいという期待を持っています。
ベンチマーク関係も不得意な私なのですが、今回は @matsumotory さんの結果を許可を得たうえでスライドに転載してご紹介させていただきました。mod_perlでの追加ベンチマークの補足情報もいただけて、本当に助かりました。会場にはRubyistの方もいらっしゃると思ったので「RubyでApacheやるならmod_mrubyもいいよ」とも伝えたかったのです。相当な機能と歴史を誇るmod_perlですが、現在進行形で開発されているmod_mrubyもmod_perlに追いつけ追い越せで開発されています。mod_perlの開発は今も現在進行形で行われていますが、mod_mrubyのような存在がmod_perl開発への良い刺激になれば良いなと願ってやみません。
20分で膨大なmod_perlのノウハウを語るには足りないと思ったので、アフターストーリーとして今後の展望を述べました。Twitter アカウント @mod_perl_info では時々mod_perlで困っている人をウォッチしてその解決策をご紹介したりしていますが、ウェブサイト modperl.info のほうは私がなかなか取り掛かれずに未完成となっています。作り途中でもいいので、今年中に何とか成果を小出しにでもしていきたいと考えています。ご声援、よろしくお願いします。
mod_perl関連の情報は他のmod_{lang}に比べて豊富ではあるのですが、日本語使用者にとって、やはり英語の情報が大多数なのがネックで、その辺りを解消していきたいと考えています。mod_perl関連のCPANモジュールの翻訳についてはmodperl.infoに閉じ込めずに、perldoc.jpへ積極的にコントリビュートしていきたいと考えてはいますが、まだ計画段階です。私の英語力の足りなさも目下の課題です。
あとどうでもいいことですが、古いネタ「キモーイガールズ」を入れたのは、いつか私が大舞台でこのネタをやってみたかっただけです。私がmod_perlをdisるはずもなく、いわば自虐ネタですね。トークの数時間前にホールで座っていた見知らぬ隣の人が、私が隣にいるとも知らず、私のトークについて「mod_perlの追いやられ感は半端ない」「mod_perlは風前の灯火」と評論してくださった事への皮肉です。もちろん現在それは実際の事であって、怒ったりはしてませんよ。入れる予定は無かったのですが、その事もあって勢いで数時間前にはてなセリフで作って入れちゃいました。はてなラボのサービス、便利!
会場での質問へのフォロー
トーク後の質問タイムで幾つか質問があったのですが、満足に答えられなかったかなという思いがあるので、ここで質問に対する少し詳細なフォローをさせていただきます。
まず消費メモリやコストの問題。
消費メモリに関しては、初期にかかる量は十分把握できるわけですが、その後mod_perl/Apacheが「太っていく」問題に関して、会場では Apache::SizeLimit / Apache2::SizeLimit を使った解決策を紹介しました。それは、規定以上のメモリを使用した子プロセスが MaxRequestPerlChild の指定に関わらず自発的に終了するという、言わば消極的な解決策ですが、「太っていく」事への対策はこのような対症療法しかないと思います(問題のプロセスを取り出して何らかの操作で「痩せさせる」事ができるでしょうか)。なぜ太っていくのかといえば、mod_perlの処理の中で大きなファイルなどメモリを大きく使用する処理の後で思惑通りの量のメモリを開放してくれなかったり、使っているPerlのバージョン自身に未知および既知のメモリリークのバグがあったり等、様々です。このような問題はスクリプトのコンパイル結果を都度捨てているPHP(mod_php)自身にも見られる問題であり、Apache固有の子プロセス終了関数apache_child_terminateも用意されているくらいです。
また上述のような対症療法以外に、初期にかかる消費メモリを抑える事もご紹介しました。Apacheの親プロセスの起動時に PerlModule ディレクティブで Encode や DBI 等のよく使用するモジュールをプリロードしておくことで、Apacheの親プロセスを子としてforkするときにCopy on Write(CoW)効果が働くことを利用して初期のメモリコストを抑えることができます。この周辺については、Perlの永続プロセスをマルチプロセスで生成するものであれば同様に考えられる問題と解決のようで、FastCGI等でも似たような感じのようです(この辺りは、例えば書籍「Mobageを支える技術」でも軽く触れられていました)。
初期メモリを抑えるためにCoWを利用することのトレードオフは、サーバの初期起動時間が長くなる事でしょうか。あと、あまり素性も分からないモジュールを親でロードしないほうが安定性の面で良いかなとは思います。
また、mod_perlのテスト環境についても質問をいただきました。
実はテスト駆動開発は私の完全に不慣れな分野でして、回答では「mod_perl自身には触れていないのに、なぜかmod_perlのテストについては『モダンPerl入門』にしこたま書いてある」なんて答えて少し笑いをいただきましたが、私の知識はそれくらいです。
テスト駆動開発全盛の昨今、この部分については皆さんも興味があるだろうと思ってスライドを用意はしたのですが、時間の都合で割愛させていただきました。サービススライドに押しやっているので、もし良かったらそちらをご覧いただけると幸いです。
会場では Apache2::FakeRequest を使った $r のフェイクオブジェクトを使うという方法をお答えしましたが、(私の不慣れのせいかもしれませんがこれは)手間はかかります。後は Apache::Test による方法などがありますが、あまり私が語れる部分は少ないのが恐縮です。この部分については今後も勉強していきたいと思います。
書籍「Practical mod_perl」にも、mod_perl1時代の情報でかつ洋書ですが、各種テストやデバッガを交えた開発手法が乗っています。こちらも興味深いので、もっと知りたい方におすすめです。「Practical mod_perl」はCreative Commonsライセンスで公開されているので、書籍が無くてもサイトから読むことが可能です。
ここまでの経緯
個人的なお話で恐縮ですが、このトークに至るまでの私の紆余曲折です。
2003年にプログラムも分からない自分を入れてくれた現在の会社。当時は学生時代に得たサーバ管理の知識で食いつなごうと思ったのですが、見事に素人知識を見透かされてかサーバは任せてもらえず、まずはテキスト処理・ログ処理からPerlを勉強することになりました。
2004年からPerlでのウェブ開発を任されるようになりましたが、当時は右も左も分からず、大変でした。mod_perlの事も言葉だけ聞くだけで、当時は「Perl CGIを速くするものだけどクセがあるから要注意」程度の理解をしていました。柱コンテンツはmod_perl1で動作していましたが、今振り返って見ると、当時はPerl CGIの高速化 (Apache::Registry) を目的とした使い方しかしていませんでした。
2005年から一人プログラマとして企画やデザイナの方々と小中規模のサイトを運営していくのですが、mod_perlの正体がつかめなかったので、私はPure CGI(Apache mod_cgi)でのPerlウェブ開発をしていました。ただ、この時からパフォーマンスを気にするようになって、柱コンテンツに使われているmod_perlを横から研究するようになりました。このころから隠れて(?)mod_perlを勉強するようになり、mod_perlはPerl CGIの高速化だけでなく、Apacheの拡張すらできるものだということを徐々に理解していきました。
これ以降の数年間は仕事の幅も広がり、後輩や一緒に働く外部の方も増え、自分がメインで担当する開発案件以外にも、PHPコンテンツの納品保守や、遊軍として他のPerlウェブ開発プロジェクトのサポートなども担当しました。その中で、それまで勉強してきたmod_perlの知識が色々なところで役に立ったのが印象的です。
数年前から、一緒に働く開発者の人数やプロジェクトの数が整理され、社内の柱コンテンツに戻ってきました。それまで得たmod_perlの見識を投入して、パフォーマンスチューニングや、mod_perlハンドラによる諸々の拡張や新規開発、mod_perl1からmod_perl2へのマイグレーション等、Registryスクリプト利用による高速化のみを目的に当初導入されたmod_perlの可能性を広げていっています。
せっかくこれだけ培ったmod_perlのノウハウを社内に閉じ込めておくのも良くないと考え、2011年からはHokkaido.pmでのトークをメインに、社外にもmod_perl情報をアウトプットしはじめました。今年2012年のYAPC::Asia Tokyo 2012での本トークは、それの集大成としたものです。
これからの計画
私はmod_perlも古くて新しい現役技術と考えてはいるのですが、残念ながら今の世の中的にニーズは少ないのが現状でしょう。私としても会社としても新しい技術を取り入れていく事が将来的なメリットであることは確かで、今後は Plack/PSGI ベースの WAF を積極的に勉強して取り入れていこうと考えています。今のところ、なんとなくMojolicious かなという気分です。少しずつ勉強中。
それでもせっかく得た mod_perl の知識をこのまま自分一人で抱えて枯らしてしまうのはもったいないと思い、今後はその知識を体系化してまとめて外に出していく作業をしていこうとしています。それがトークでも触れたアフターストーリーであり、Twitterアカウントやウェブサイトの開設の野望でもあります。
今回のYAPCのLTソンでもミートアップがありましたが、地域pmが盛んになってきたことは嬉しい限りです。もし地域pm等のPerlの集まりで「mod_perlについて聞きたい」という要望があれば、声をかけてくだされば時間やお金をやりくりしてぜひ訪問したいです(経費をいただいて呼ばれる身分ではありませんので、費用は自分でなんとかします)。
繰り返しになりますが、今回のYAPCでの「モダンmod_perl入門」は、私の数年間のmod_perl開発の集大成的な位置付けでトークしました。今後はmod_perl以外のジャンルにも視野を広げて、求められればmod_perlの事を語れる準備は怠らないものの、今後自発的に発表するものは、多くの皆さんの興味を引く別の話題ができればなと考えています。
今後とも、mod_perl を含めた Perl の世界で、皆さんのお役に立てるアウトプットをしていきたいと考えていますので、どうかよろしくお願いします。ここまでの長文、読んでいただきありがとうございました。