6/22 修正: mod_perlじゃなくてただのapache moduleだった。自分の中でmod_perlとapache moduleが同じ箱に入ってて違和感なくmod_perlって書いちゃった・・・
-----
まぁそんな事をしてるのであんまり表側のアプリとかを直接触ったりはしないのですが、あるとき突然某システムの話をしてるときに「あ、これオブジェクトストレージに突っ込もう」という話になりました。聞くともう大分前から使ってるSで始まって、Tが間にあって、Fで終わるオブジェクトストレージの事らしいんですが、これのフロントエンドがmod_perl apache moduleで書かれてるわけですよ。
・・・テストできない(しづらい)じゃん!
そんなわけでAPIの基本部分だけでいいからPSGIのがほしいよね!ってことになり、Plack-App-STFってのを書いて、これを通してテストするようにしてみた・・・のが運の尽き。IRCでどっかのCTOさんが「本体も書き直してよ」的な事を言うわけですよ。
しょうがないですよね。昔はどうであれ僕も今はサラリーマンですからね。役職にChiefってつく人に言われたらやりましょう。
というわけでとあるオブジェクトストレージのフロントエンドがmod_perl apache moduleで書かれてたのを完全にPSGIベースに直して、この間からすこーーーしずつリプレースをしようという事で作業をしている。
元々動いているシステムなので全部入れ替わるのは大分先の話だろうけど・・・
で、まぁまだソースコード出してないけど、今回これを作るのにやったことやなんとなく思ったことなど。
仕組みとしてはディスパッチャーがあり、こいつが裏方にある複数台のストレージノードにGET/PUT/DELETEを発行する形でデータのやりとりをしている。例えば GET http://stf/hoge.jpg とかしたら、裏にN台ある/hoge.jpgを保管してあるストレージの中から一台を選んでそいつのデータをクライアントに送る。
これまでのコードは mod_proxyに近いことを apache module内でやってたんだけど、Plack/PSGIでProxyとかなんかPerlのリソースの無駄遣いな気がしたので mod_reproxyを使う事にしたのが大きな変更点のひとつ。要は新しいバージョンからディスパッチャーがまずランダムにHEADを裏方に発行して、一番速く、かつ200が帰ってきたストレージのURLをX-Reproxy-URLでmod_reproxyに送るというもの。
このmod_reproxyは弊社の内部事情でフロントがapacheなので@kazuho氏謹製のmod_reproxyを使っている・・・が、一部問題が出たので色々俺俺な変更を入れたmod_reproxyを現在はつかっている次第。マージ/レビューを待っている今日この頃!
あと、裏方にHTTPリクエストを送る方法なんだが、これ複数リクエストを同時に送って待つ、みたいなコードだからここだけ非同期にしたら速いんじゃね?とか安易な考えで実装してみたら正直大して速くなかった。まぁそこだけイベントループのスタート・終了がある分オーバーヘッドがあるわけだし当然っちゃあ当然なんだけど、それよりFurlの速いこと速いこと。もうこの手のAPIとかを叩く系のクライアントは本当Furlだけでいいよ。変にI/O多重化するより普通のループでFurlをぶんまわしたほうが全然速い。
最後に、はまったこと。歴史的な事情によりID生成の際のロック機構にSysV IPCを使ってるんだけど、semaphoreはグローバルだってことをみんな忘れないでな!特に、Starletとかの中のアプリでsemaphore使ってると、時々世代交代が起こることを忘れるな!DESTROYとかに $sem->removeとか入れておくと確保したはずのsemaphoreが子プロセスに勝手に消されてて他のプロセスが簡単に死ぬぜ。こういうのはDESTROYとかの中で if ($$ == $parent_pid) とかしてちゃんと「リソースを作ったプロセス」が「リソースを解放するプロセス」かどうか確認してから解放しましょう。
まぁそんなわけでmod_perl apache moduleだったオブジェクトストレージをPSGIで書き直した。正直大分コードの見通しもよくなった気がするし、なによりMiddlewareとかも使えるし、拡張性がぐっとあがったので満足。パフォーマンスはまったく遜色ないかと思う。
ロケタッチとかの一部サービスは今ヘッダを見るとPerlが裏で動いているのが見えるはずですね。しかしこれは開発支援なのか?という疑問は未だに残っている。
おしまい。