前回 に続いて、12/28、 Rails勉強会@東京第2回 に行ってきた。今回も秋葉原某所にて開催。
集合
駅前広場を見渡すと、shachiさんが最初に来ていたみたい。御挨拶して、2人して目印の AWDwR を取り出すと、すぐにもう御一方やってきた。目印を見るまでshachiさんが分からなかったみたい。
そんな感じでしばらくすると半分ぐらいは集まってきて、でもそれ以上は人が増えない。中央線で事故があった影響だろうか。
前回と同じく、このなんだか妙な集団を見て、何の集まりだろうと寄ってきてはAWDwRを見て不可解といった様子で去っていく人が数人。「(寄ってきた人が)もっと面白いパフォーマンスしてくれればネタにしようもあるのにね」って誰かが言っていたけれど、そりゃ酷だ。
会場
とりあえず前半セッションの準備っていうことで、数人残って遅れている人を待ち、残りは会場に移ることになった。
今回も オープンスペース 形式で、1セッション90分を2回。今回は私の ポジションペーパー はAJP一色だ。個人情報を伏せたほかは配布したままのものが下記。前回、 畠山さん が「日記の名前書いてくれないと誰が誰だか分からないよね」とおっしゃっていたので、blog名を書いてみた。そだなー。畠山さんの名前は覚えていなかったけれど「ちくわ」さんと聞いたらすぐ分かったもんなー。
なお、上記ポジションペーパー中のグラフでは、CGIのケースだけ実は1 thread * 100 timesのデータです。実際1000回リクエストしたら、10倍とはいいませんが、もっと掛かると思われます。
前半セッション
事前の立候補受け付けでは私の「AjpRails」しか前半のセッションの立候補がなかったので、shachiさんと「この人数が1セッションに集まったらソースをタコ殴りにされるよー。他の立候補があがってくれないと困る」と話していた。結局、会場で何件が立候補が出てきて、4つのテーブルに分かれた。なんとかタコ殴りにされずに済んだ。
- AJPでRails - Apacheをつなぐ
- SwitchTowerの光とカゲ
- デザインとRails( 前回の続き)
- 後半セッション1(Testing)の為に本の前半をながめる
私は「AJPでRails - Apacheをつなぐ」のオーナーを務めさせていただいた。私が開発中の、Rails - HTTPd接続の第5(?)の選択肢、 AjpRails を紹介する。
すわ、セッション失敗か
今回はノートPCを復活させて、 無線LANインターフェースも用意して 持っていった。デモ用のデータもセットしてあるし、会場のプロジェクターも借りて準備は万端の筈だったのだけれど、会場の無線LANにどうやっても繋がらない。
セッション失敗かという危ういところに、救いの神のかくたにさんが現れて、結局、インストールシーンのデモとソースレビューはかくたにさんのマシンの御世話になった。デモ用データばっかりはどうしようもないし、他の方はノートPCがなかったので私のマシンで、ApacheもAjpRailsもブラウザも全部ローカルホスト内で、しょぼいデモンストレーションをやった。私のノートじゃXが重すぎるみたいで動作がもっさりするので、コンソール画面でブラウザはw3mっていう、なんというかビジュアル的にインパクトの無いデモになってしまった。
AjpRailsのインストール
gemがあればAjpRailsのインストールは簡単。
# gem install ajp-rails
以上。ruby-ajpも必要なので、依存関係をインストールするかどうか聞かれる筈。
gemがなくても青木さんのsetup.rbを使っているので、ajp-railsとruby-ajpのアーカイブを展開した中のInstall.jaを見ながら、各々おなじみの手順を踏めばすぐにインストールできる。
AjpRailsの設定のしかた
Apache2で、mod_rewrite, mod_jkが入っているものとしましょう。まずは、Tomcatと同じく、ワーカーとマウントの設定が必要。似たような設定例はajp-railsパッケージのexamples/の中に入ってはいるけれど。
簡単のため、ルートパスに直接Railsアプリケーションをマップしてしまうとして、そのアプリケーションが物理ディレクトリ /home/yugui/depot_final/ 以下にあるとすると、設定はこんな感じになる。
バーチャルホストはこう。
NameVirtualHost *:80 <VirtualHost *:80> ServerAdmin webmaster@localhost ServerSignature On DocumentRoot /home/yugui/depot_final/public <Directory /> Options FollowSymLinks AllowOverride None </Directory> # ログ設定とかはよしなに。 CustomLog /var/log/apache2/access.log combined ErrorLog /var/log/apache2/error.log LogLevel warn RewriteLog /var/log/apache2/rewrite.log RewriteLogLevel 2 JkLogFile /var/log/apache2/mod_jk.log JkLogLevel warn JkEnvVar SERVER_SOFTWARE "" <Directory /home/yugui/depot_final/public/> RewriteEngine on RewriteRule ^$ index.html [QSA] RewriteRule ^([^.+])$ $1.html [QSA] RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ /ruby-ajp/$1 [QSA,L] </Directory> JkMount /ruby-ajp/* depotlb </VirtualHost>
workers.propertiesはこう。
worker.list=purposeajp,depotlb # Definition for Ajp13 worker # worker.purposeajp.type=ajp13 worker.purposeajp.port=3009 worker.purposeajp.host=localhost worker.depotlb.type=lb worker.depotlb.balanced_workers=purposeajp
- まず、mod_jkの接続ワーカーを宣言する。これはworker.listプロパティにカンマ区切りのワーカー名を設定することで行う。ドキュメントによるとワーカー名は[0-9A-Za-z]+でないといけないので、ハイフンとか入れないように注意。
次に、各ワーカーの設定を行う。
- typeはワーカーが使用するプロトコル。ajp14とかjniはAjpRailsが対応していないので注意。
- hostとportは接続先のアプリケーションサーバを指定する。
- typeに"lb"を指定すると、mod_jkが提供するロードバランサに仮想的に接続することになる。下位に複数のアプリケーションサーバーをぶら下げて、一個の仮想的なアプリケーションサーバーとして見えるようにして、内部では適当に負荷分散してくれるわけだ。balanced_workersに下位のワーカー名をカンマ区切りで書けば良い。
私のマシンがちゃんと無線LANに繋がっていたら、他の人にもAjpRailsを立ち上げてもらって、その分のworkerを設定してロードバランサを実演したかったのだけれど、今回はロードバランサの下にぶら下がっているのはlocalhostに接続するpurposeajpのみ。バランサの意味なし。哀しい。
で、httpd.conf側はここら辺が問題。
<Directory /home/yugui/depot_final/public/> RewriteEngine on RewriteRule ^$ index.html [QSA] RewriteRule ^([^.+])$ $1.html [QSA] RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ /ruby-ajp/$1 [QSA,L] </Directory> JkMount /ruby-ajp/* depotlb
URL rewritingまわりはrails標準の .htaccess と同じだから、railsの設定した人にはおなじみ。違うのは、fcgiとかのファイルへrewriteするのではなくてマウント用の仮想ディレクトリにrewriteすることだけ。
マウントも、mod_jkを使っている人にはおなじみ。マウントする仮想パスのパターンと、そのパスを処理するワーカー名を指定する。今回はロードバランスワーカーに処理させているけれど、前述の通り1つしかサーバーが動いていないから直接purposeajpに飛ばしても同じ。
AjpRailsの起動のしかた
インストールすると、PATHの通ったところにajp-railsっていうコマンドが出てきてる筈。以下、これを使う。gemを使わないでインストールした場合で、rubyを野良makeしてたりすると、shebangの中のrubyのパスを直してやる必要があるかもしれない。まぁ、野良makeするような人には言うまでもないことで、失礼を。
ajp-rails --help とすると、いろいろコマンドラインオプションが出てくる。
Usage: ajp-rails [options] -p, --port=PORT Listens to the specified port. Default: 8009 -h, --host=IP Binds rails to the specified ip. Default: 127.0.0.1 -e, --environment=RAILS_ENV Specifies the environment to run this server under (test/development/production). Default: ENV['RAILS_ENV'] || 'production' -l, --location=LOCATION The base of the application's virtual path. Default: / -d, --directory=DIRECTORY The base of the application's physical path Default: . --prefix=PREFIX The prefix of the ajp-mounted URLs. --suffix=SUFFIX The suffix of the ajp-mounted URLs. --serverid=ID The unique ID to identify this rails process, which is for sticky session. The ID can contain only [a-z][A-Z][0-9], and case insensitive. --jvm-route=ID This is equal to --serverid --daemon Makes Rails run as a daemon -c, --config=FILE Reads options from the specified file. Thefile must be YAML file.
英語に自信がありません。変だったら誰か直してください。
で、起動時にいちいちこれらを全部タイプする必要はない。外部設定ファイルにYAML形式でlong option名をキーとするHashを書いてやれば --config=FILE で読み込める。上のApacheの設定に従うとこんな感じだ。
host: localhost port: 3009 environment: production location: "/" directory: "/home/yugui/depot_final" prefix: /ruby-ajp jvm-route: purposeajp&verb(</pre>)
- hostは今回はlocalhostだけでいい。もし、別のマシンのHTTPdからRailsにつなぐなら、nilを指定すると任意のホストからの接続を受けいけるので"host: ~"とか適当に。
- portはworkers.propertiesの設定と合致するように。今回は3009にしてみたけれど、あんまり深い意味は無い。
- environmentはrailsの3つの環境のうちの1つ。
- locationは、Railsに割り当てた仮想パス。Cookieを設定するときとかに使う。今回はルートにしたのであった。
- directoryは、Railsアプリケーションの配置されているファイルシステム上のディレクトリ。この辺を指定しなければいけないのがいまいちDRYじゃなくて格好悪い。
- prefixは、マウントするために使用した仮想ディレクトリ名。内部では、rewrite後転送されてきたREQUEST_PATHから、このprefixを落としてRailsに渡している。ここで指定するか、もしくは適当にRailsのRoutingを設定してやらないとコントローラーの同定に失敗すると思う。
- jvm-routeは、Tomcatでいうserver.xmlの xpath:/Server/Service/Engine/@jvmRoute と同じで、ロードバランスするときのアプリケーションサーバーの識別に使用する名前。mod_jkにおいては、対応するワーカー名と同一に設定しなければいけない。この辺もDRYじゃなくて格好悪い。設定をまちがえるとsessionがstickyにならないので注意。
他に、suffixとかもある。例えば、特定の拡張子で終わるリクエストをrailsに処理させようとするなら、httpd.confで
JkMount /*.ext workername
とか設定して、suffixに".ext"を設定すればよい。後の懇親会で出た話題だけれど、偉い人がJSPを使えと押しつけてきた場合、*.jspをRailsに転送してしまえば見かけ上は分からない。
さて、そんな感じで設定が終わったら、 ajp-rails -c CONFIG-FILE で起動する。で、w3mで http://localhost/store/ を開くと、めでたくAWDwRのdepotアプリケーションが動いていましたとさ。でもコンソールではビジュアルがさびしい。
なお、AWDwRのサイトで配布されているDepotはRails 0.13以前の形になっている。前回の「CHANGELOG」セッションで出たような手順を踏んで移行させないとAjpRailsではうまくいかない部分があるので注意。AjpRailsはRails 0.14以降にのみ対応しております。
ソース読解
以降はかくたにさんのマシンにて、エントリーポイントのlib/ajp-rails/rails-runner.rbから順にソースを読んだ。淡々と。
適当に、私がAjpRails実装中に発見したRailsのあれこれを喋ったりも。RailsのDispatcherの実装がおかしい件とか( 後半のレポートで詳述)。Object#sendをあちこち使ってる件だとか。
セッションの参加者にRailsをYARVで動かそうとして無理だったという方がいらしたけれど、そうなのだ。他の部分は知らないけれど、少なくともprivateメソッドを無理矢理呼ぶ目的でObject#sendをあんなに使っていたら、 Ruby 1.9の仕様変更 により、動くわけないのだ。
オーナーが頼りないばっかりにかくたにさんに頼りっきりで、本当に申し訳ない思いだった。でも、かくたにさんが後で「ソースをプロジェクターで写してみんなで読む形式は満足感がある」と言ってらして、ちょっと救われた。
冒頭のポジションペーパーにも書いてあるように、AjpRailsは今は遅い。でも、UNIXドメインソケットへの対応がまだだったり、「時機尚早な最適化」に陥るよりはきちんと書こうという方針だったりして、まだまだ速くなる予定だ。セッションでは、「CGI系はオブジェクト指向から見ては必ずしもいいインターフェース設計じゃない。いずれはAjpRailsでもってdispatcher.fcgiに取って代わる」と大言壮語してみた。
他のセッション
他のセッションはこんな感じだったらしい。
SwitchTowerの光とカゲ
某大企業で使ったときの様子とか、貴重な発言が聞けたらしい。オーナーになってなければこっちも聞きたかった。moroさんが 詳しくレポート している。
デザインとRails
どうしてデザイナーの人はHTML Template理解してくれないかなーとか。CSSをどうするかとか。
本の前半をながめる
ながめたらしい
続
後半 に続く