技術メモ: 2008年9月アーカイブ

photo by rudolf_schuba

masuidriveの人から、ご意見聞かせて、と連絡が来たので、がんばって書いてみます。
masuidrive on rails - Webでの非同期処理を考えてみる [長い記事だけどコメント求む!]
Life is beautiful: マルチスレッド・プログラミングの落とし穴、その2

要するに、重くなってきたサービスに対して、むやみにサーバを増やさないでどうやってパフォーマンスを改善しましょう?全部の機能を同期的に処理する必要はないんじゃね?という話だと理解しました。

ボク程度の人の意見が必要というよりは、何かしら「あっ!」って気づくきっかけが欲しいのだろうから、遠慮せずにだらだらと。
「その程度のことはわかっとるわいっ!」という部分が多いと思いますが、そこはご容赦ください。

全部を非同期にすると...

中島さんの記事で

アクセス数が上がると、ユーザーがした投稿がデータベースに反映されるまでの時間がかかるようになるが、それが直接的におもてなしの低下に繋がることはない
と書いてあって「え~っ?」とまず思いました。

最近ブログのコメント欄なんかで、(スパムを防ぐために)管理者承認後に反映されます、というブログが増えているのですが、これは明らかに、おもてなしの低下につながっています。
単純な話で、自分が投稿したコメントがどう見えるかすぐに確認できない分、ユーザーさんはできあがりイメージを確認せずにその場を離れないといけないわけで。その場でできあがりを確認してから離れられるのに比べて不便なのは確かでしょう。

masuidriveの人の記事を見ると、「でも全部を非同期にする訳にはいかないし」って言われているので、そんなことは承知の上で、人間以外には非同期でいいんじゃね?という意図なのだとは思いますが。

あれ。でも全部非同期って、意外とありかもしれない。だって現にブログのコメントが非同期に反映されることについては、ユーザーの非難囂々という状態にはなっていなくて、それなりにみんなの同意が得られつつあるように見えます。
それだったら、投稿とか削除についても、「ちょっと時間がたってから反映されます」と一言表示されるだけで意外と許されるのかも。

エラーがあったらどうするか。photoshareの場合、幸い(?)ユーザー登録しないとコメントできないシステムみたいですので、
#iPhone持ってないので、詳細は知りませんw
それだったら、エラーになったらメールする、でもいいんじゃないでしょうか。
あと、よくしらんのですが、iPhone上のサービスって独自の(WEBじゃない)アプリが動いてるんですよね?であればそっちに表示させるとか。

同期と非同期をわける方法

ただ、そうやって非同期にすることが一般化すると何が起きるか。
なんだかんだいったって同期でスムーズに動いた方が嬉しいのは事実なので、そうすると、ユーザー数の少ない小規模サービス(技術者が片手間で作ったみたいなの)と、
リソースに余裕のある超大手サービス(YahooとかGoogleみたいな大手がはじめる新サービス)は同期で動いて、
photoshareのような、お金とサービスのバランスをとらないといけないところだけが非同期で機能を提供することになります。
これは痛い。競合に提供できるサービスを自分たちは提供できません、ということになるんだから、これは厳しい。

そうすると、やっぱり全面非同期化は厳しいんじゃないかな、と。
リアルタイムの情報を必要としないRSSとか、クローラーとかには非同期で返しつつ、ユーザーさんの要求はリアルタイムで返す必要があるんじゃないのかなぁ。

じゃあ、同期と非同期をどうやってわけるか。

 コントローラごとに実行するmongrelを振り分けるようなルールをリバースプロキシに書けばある程度回避できますが、どのように振り分けるのか決定するのは困難です。(Feedなら簡単だけどもっと難しいケースもあるよね)

 このように実はアクションごとに優先順位があります。Feedやランキングと言った部分は、反映が遅くてもほとんど問題になりませんが、自分の写真リストや写真そのものはすぐにアクセスできるようにしたいのです。
 現在のRailsはコントローラごとに優先順位を付けるような処理は苦手なので、これを行うには、なんらかの仕組みが必要になると思います。

問題は二パターンあって。
1.create,update,delete系の要求以外を別サーバに振り分けたら問題が解決する場合
2.それでは負荷対策として不十分で、create,update,delete系であっても一部は非同期にする必要がある場合

1.だったら問題は簡単で、railsで動作する同期動作サーバと、rsyncか何かで同期サーバの情報をミラーして提供する非同期サーバを用意して、リバースプロキシ部分の振り分けをがんばればいい話です。
sv_idea1.jpg
#十分難しいのですけどw まあお二人ならきっとできるでしょう。

問題は2.の時で。アーキテクチャはこんな感じかなぁ。非同期でいい機能はWEBサービスとして切り出して、フロントサーバはバックエンドサーバに投げちゃう。
sv_idea2.jpg
#当たり前ですけど、本当にサーバを4台以上用意せよ、という話ではなくて。物理的に同じサーバ上でフロントとバックエンドの機能が動いていたってかまわないです。負荷が耐えられるんだったら、ですけど。

バックエンドサーバに要求される機能はこんな感じ。
・要求を受け付けて、キューに入れる
・応答は、静的に生成してあるHTMLかなにかをそのまま返しちゃう
・適宜キューにある処理を実施して、静的HTMLをアップデートする

railsで実現するとすると、
・要求を受け付けたら、それをDBに入れて、生成済みのHTMLを返す。ここはrailsで普通に作れるはず。
・キューにある処理を実施する部分は...

キューの処理は、rakeタスクをcronとかで叩くようなぬるい処理で間に合うんだったらこんな苦労していないから、やっぱりぶんぶん回るサーバプロセスが必要になりますね。
ここでrailsいらないじゃん、という話になるわけか。

いかん。masuidriveの人と同じ結論になってしまった^^;
でも、ここまでをふまえると、やっぱり独自で作るのがいい、という話になると思います。要求とは無関係にぶんぶん回っている時点でもはやWEBサーバじゃないですから、それに適したアーキテクチャのものを書く必要があるんじゃないかなぁ。

なんだかまとまらん話ですが、思うがままに書いてみました。何かしらヒントになるような部分があれば幸いです。



 Windowsからlinuxサーバにアクセスする日本人の標準ツールPuTTY ごった煮版は、設定をレジストリじゃなくてiniファイルに保存することができます。
 今まで設定をレジストリに保存していた人は、ゑBLOG: PuTTYごった煮版 レジストリ<->INIファイルコンバータを使うと設定を変換することができます。

 ところがこれが、どうもうまく動かない。スクリプトは動作するのだけれど、出力されたputty.iniには
[Generic]
UseIniFile=1
しか書かれていない、ということになって困りました。

コチョコチョしてみたら原因が分かったので、困った人向けのメモ。

原因:
 WindowsXPのregeditは、utf16(16ビット単位で文字を扱うコード)でファイルに書き出すみたいです。
reg2ini.pl(というか、ActivePerlとかその辺の処理系)はutf8を前提としているので、これだと正規表現がまったくマッチしなくなります。

ということで、出力された.regファイルを一度秀丸エディタか何かで開いて、utf8に変換してからreg2ini.plを使うとうまく動作します。

追記
regeditでエクスポートするときに「Win9x/NT4 登録ファイル」を選ぶという手もあるらしいです。
regedit.JPG


 Amazonが運営するサーバ仮想化技術であるAmazonEC2&S3を使ってみました。

やり方とかは増井さんがとっくに説明されていますので、
はじめてのAmazon EC2&S3 ~これからの新サービスの公開の形~
ここでは使ってみた感想とかを。

意外といける

 聞き慣れない単語が多かったので、これはどうも今までの技術とは別系統っぽいなぁ、
はやらなかったときが悲惨だからもう少し様子見、とか思って先送りしてきたのですが^^;
やってみた結果、そんなに変な技術ではなくて、自分の知っている技術の延長線上にあるシステムだと分かりました。
 vmwareを使ってWindowsの上でlinuxを走らせたことのある方は分かると思うのですが、vmwareが動いてしまえば、
その下のホストOSは、Windowsだろうとlinuxだろうと、あまり関係がなくなってしまいます。
Windowsで作った仮想マシンイメージをlinuxで動いているvmwareに持って行ってもそのまま動作しますよね。
この考え方を延長すると、ホストは正体不明のOSであってもかまわないわけで。
正体不明のOSの上に何台でも仮想マシンを走らせることができるようにしたのが、AmazonEC2です。
なので、AmazonEC2の上でゲストOSが動いてしまえば、あとは普通のlinuxと同じように使うことができます。

マシンイメージが便利

 vmwareでは、新品の仮想PCをくみ上げてそこに自分でOSを入れるのが基本でしたが、AmazonEC2では、すでにあるマシンイメージ(AMI)を使うのが基本です。
RedhatやCentOS,Ubuntuなどの各種linuxイメージが公開されているので、このコピーを使っていきなりマシンを起動させることができます。
amis.JPG
で、このマシンイメージがなにげに便利です。
いままで、CentOSをインストールしたら、その後Rubyを入れて、RubyGemも入れなくちゃ、RubyGemはyumにないから自分でrpm作らないとね、そのためにはrpmbuild入れて...
というような作業が必要だったのですが。rightScaleさんが公開しているCentOSのイメージでは、RubyはもちろんGemもsqliteもsubvesionも、全部すでにインストールされていました。
これは楽ちん。

もちろんこれは、自分の希望と異なるものが入っていたら「余計なことすなっ!」ですが、AmazonEC2を借りてその上でWebサービスを作ろうという人にはおおむね妥当なソフトがインストールされていて、これは便利、と思いました。

自動拡張してくれるわけじゃない

 「AmazonEC2は負荷に応じた拡張が容易」といわれていたので、負荷が高くなったら勝手にCPUの性能が上がったり、ディスクサイズが自動的に拡大されたりするサービスなのかな、と思っていたのです。
そんな怪しいマシンだから、きっと普通のOSは動かないんだろうな、と思って警戒していたのですが。
 べつにそんな怖いサービスではありません。仮想マシンを動かすことができますが、それだけです。ただ、サーバの増設が必要だ!となったときに、新しいマシンを買ってきたり、そこにOSを入れたりしなくても、AMIから同じ構成のマシンを何台でも立ち上げることができるので、拡張が便利、とそういうことです。
 なので、スケーラビリティを考えないサービスを適当に作っても何とかしてくれるわけじゃなくて、ちゃんとスケーラブルになるようにサービスを設計しておく必要があります。
はじめてのAmazon EC2&S3 ~これからの新サービスの公開の形~:第4回 自分用のイメージファイル(AMI)を作ろう|gihyo.jp ... 技術評論社

 なんにも考えずにサーバが勝手に何とかしてくれないかな?とかずぼらなことを考える人は、グリッドホスティングみたいなサービスがオススメです。

#まあこれはこれでいろいろ難しいのですけどね。