Async Programming on Ruby

5,052 views

Published on

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,052
On SlideShare
0
From Embeds
0
Number of Embeds
1,014
Actions
Shares
0
Downloads
0
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Async Programming on Ruby

  1. 1. RubyでEvent-DrivenなWebプログラミングを楽しむ環境が整ってきた件<br />@KazkiMatz<br />
  2. 2. Background<br />’08 3月<br />’07 4月<br />国土交通省<br />’02 4月<br />’83 9月<br />’07 3月<br />’09 12月<br />IPA未踏案件<br />京都大学<br />工学部<br />電気電子工学科<br />head<br />’06 8月<br />’09 11月<br />’08 4月<br />
  3. 3. (復習)Event-Drivenなアーキテクチャが重要である理由<br />20ms<br />100ms<br />80ms<br />前処理<br />DBレスポンス待ち<br />View<br />レンダリング<br />View<br />レンダリング<br />前処理<br />DBレスポンス待ち<br />View<br />レンダリング<br />View<br />レンダリング<br />DBレスポンス待ち<br />DBレスポンス待ち<br />前処理<br />View<br />レンダリング<br />前処理<br />CPUリソースを有効活用するには?<br />-> 1CPUにつき、2インスタンス以上立ち上げる<br />
  4. 4. 思考実験<br />10ms<br />10sec (10,000ms)<br />40ms<br />前処理<br />バックエンドレスポンス待ち<br />後処理<br />前処理<br />バックエンドレスポンス待ち<br />後処理<br />…<br />1CPUにつき、約200インスタンス必要!?<br />
  5. 5. 思考実験<br />Railsの場合:<br />1インスタンスにつき、フットプリントが100MB<br />×200個<br />= 20GB<br />現実的ではない<br />C10K問題<br />
  6. 6. 解決策<br />Event-Drivenに処理する(Reactorモデル)<br />軽量スレッドを活用(Fiber, Neverblock)<br />コンテキストの保持面から考えると…<br />1 ⇒ closureベース(JSにそっくり!)<br />2 ⇒ 軽量スレッドの継承ベース<br />
  7. 7. 現時点での顔ぶれ(Ruby界隈)<br />EventMachine<br />Async-Webサーバ<br />Thin<br />Ebb<br />Async-Webフレームワーク<br />Cramp<br />async_sinatra<br />周辺環境<br />Gearman<br />
  8. 8. Gearman?<br />分散処理フレームワーク<br />Event-Driven サーバプログラミングと抜群に相性がいい(重い処理をバックエンドに投げ、レスポンスが帰ってくるまで待つ)<br />ブロックしないクライアントが無かったので、EventMachine::Protocols::GearmanをGithub上で作成中。<br />http://github.com/KazkiMatz/em-gearman-client<br />
  9. 9. Cramp?<br />登場して間もないWebフレームワーク<br />手軽にEvent-DrivenなWebアプリケーションを書ける<br />EventMachineを使っている<br />Rackをサポート<br />Thin / Rainbows! 上で動作<br />http://m.onkey.org/2010/1/7/introducing-cramp<br />
  10. 10. Cramp<br />JSONを返すAPIエンドポイントの実装例<br />classTestController < Cramp::Controller::Action<br />on_start :main<br />def main<br />~~~<br />self.respond({ … })<br />end<br />defrespond hash<br /> render hash.to_json<br /> finish<br />end<br />end<br />
  11. 11. Cramp<br />defmain<br /> res = {}<br /> joint = AsyncJobsJoint.new<br />joint.callback = Proc.new{ self.respond(res) }<br /> ticket4memcache = joint.take_ticket<br />@@cache ||= EM::P::Memcache.connect'localhost', 11211<br />@@cache.get(someKey.to_sym){|item|<br /> res[:memcache_response] = item if item<br />joint.return_ticket ticket4memcache<br /> }<br /> ticket4gearman = joint.take_ticket<br />gearman = EM::P::Gearman.connect‘localhost', 7003<br /> task = gearman.create_task(‘someJob’, someInput)<br />task.on_complete{|item|<br />gearman.close_connection_after_writing<br /> res[:gearman_response] = item<br />joint.return_ticket ticket4gearman<br /> }<br />task.on_fail {<br />gearman.close_connection_after_writing<br />joint.return_ticket ticket4gearman<br /> }<br />task.queue!<br /> ticket4db = joint.take_ticket<br />User.where(User[:id].eq(params[:user_id])).first {|user|<br /> res[:db_response] = user<br />joint.return_ticket ticket4db<br /> }<br />end<br />全体終了後の<br />コールバックを<br />登録<br />Memcached, Gearman, MySQLの3者に、“同時並行的に”データを取りに行き、AsyncJobsJoint(後述)で待ち合わせている。<br />
  12. 12. Cramp内、待ち合わせのお供に…<br />classAsyncJobsJoint<br />defcallback= proc<br />@callback = proc<br />end<br />deftake_ticket<br />@tickets ||= []<br /> ticket = (@tickets.max || 0) + 1<br />@tickets << ticket<br /> ticket<br />end<br />defreturn_ticket ticket<br />@tickets.delete(ticket)<br />@callback.callif@tickets.empty?<br />end<br />end<br />
  13. 13. Summary<br />2007年にEventMachineが登場してはや3年、環境はかなり整ってきた<br />使いこなせるかどうかで、必要なサーバリソースが一桁以上変わることがある<br />Crampよさげ<br />一つのアプリケーション内で、同期Webフレームワーク(ex. Rails)と非同期Webフレームワーク(ex. Cramp)を使い分ける<br />一歩踏み出すのに、今ほどいい時期はない<br />
  14. 14. ご清聴ありがとうございました<br />松本 一輝 (KazkiMatz)<br />email: kazki.matz@gmail.com<br />blog: http://d.hatena.ne.jp/kazuk_i/<br />twitter: @KazkiMatz<br />

×