Your SlideShare is downloading. ×
0
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

0-60 with Goliath: Building High Performance Ruby Web-Services

48,312

Published on

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

No Downloads
Views
Total Views
48,312
On Slideshare
0
From Embeds
0
Number of Embeds
15
Actions
Shares
0
Downloads
69
Comments
0
Likes
23
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 0-60 with Goliath<br />building high-performance (Ruby) web services<br />Ilya Grigorik<br />@igrigorik<br />
  • 2. conn =EM::HttpRequest.new('http://gogaruco.com')<br />r1 =conn.get :path => "speakers.html", :keepalive => true# 250 ms<br />r2 =conn.get :path => "schedule.html"# 300 ms<br /># wait until done …<br />Answer:<br />All of the above!<br />Total execution time is:<br />250 ms<br />300 ms<br />550 ms<br />~ 65% truthiness<br />~ 25% truthiness *<br />~ 10% truthiness **<br />HTTP Quiz<br />this is not a trick question…<br />
  • 3. “SPDY? We can’t even get HTTP right…”<br />the why, how, and how-to of Goliath<br />
  • 4. Server<br />Client<br />20 ms<br />TCP handshake<br />HTTP Request<br /><ul><li>headers, body</li></ul>40 ms<br />processing<br />Multi-part body (*)<br />Terminate connection<br />HTTP 1.0<br />RFC 1945 (1996)<br />+ 40ms TCP setup (network)<br />+ 20ms request (network) <br />+ 40ms processing <br />+ 20ms response (network)<br />66% of time in network overhead<br />
  • 5. Benchmark client RTT, not just the server processing time<br />A public service announcement…<br />
  • 6. Keep-alive<br /><ul><li>Re-use open connection
  • 7. No multiplexing, serial
  • 8. Default to “on”</li></ul>Pipelining<br /><ul><li>No multiplexing
  • 9. Parallel requests</li></ul>HTTP 1.1<br />RFC 2616 (1999)<br />
  • 10. + 40ms TCP setup (network)<br />+ 20ms request (network) <br />+ 40ms processing <br />+ 20ms response (network) <br />x 40ms TCP setup (network)<br />+ 20ms request (network) <br />+ 40ms processing <br />+ 20ms response (network) <br />200ms for two requests<br />Small win over HTTP 1.0<br />Keep-alive<br />RFC 2616 (1999)<br />* One gotcha…<br />
  • 11. Net:HTTP<br />Keep-alive<br />RFC 2616 (1999)<br />Connection: close < ugh!<br />
  • 12. + 40ms TCP setup (network)<br />+ 20ms request (network) <br />+ 40ms processing <br />+ 20ms response (network) <br />60% of time in network overhead<br />120ms for two requests – 50% improvement!<br />Pipelining<br />RFC 2616 (1999)<br />
  • 13. Connection setup: 50ms<br />Request 1: 300ms<br />Request 2: 250ms<br />Total time:<br /> ~250 ms<br />~300 ms<br />~350 ms<br />~600 ms<br />Pipelining Quiz<br /> RFC 2616 (1999)<br />
  • 14. There is just one small gotcha…<br /> Making HTTP Pipelining Usable on the Open Web<br />http://tools.ietf.org/html/draft-nottingham-http-pipeline-01<br />
  • 15. conn =EM::HttpRequest.new('http://gogaruco.com')<br />r1 =conn.get :path => "speakers.html", :keepalive => true# 250 ms<br />r2 =conn.get :path => "schedule.html"# 300 ms<br />Total execution time is:<br />250 ms<br />300 ms<br />550 ms<br />Keep-alive what? HTTP 1.0!<br />~ 65% truthiness<br />~ 25% truthiness *<br />~ 10% truthiness **<br />Good: Keep-alive + Pipelining<br />Bad: Keep-alive + Garbage<br />“I’m confused”<br />HTTP in the wild<br />it’s a sad state of affairs<br />Keep-alive: mostly works – yay!<br />Pipelining: disabled (except in Opera)<br />
  • 16. HTTP can be a high-performance transport<br />Goliath is our attempt to make it work <br />
  • 17. <ul><li>Goliath == v3 API stack
  • 18. Open source in 2011
  • 19. Growing community
  • 20. “Social Analytics”
  • 21. Rails frontend
  • 22. Ruby backend
  • 23. 95%+ of traffic via API’s</li></ul>+<br />+<br />Brief History<br />Goliath @ PostRank<br />
  • 24. Rails<br />…<br />HTTP API<br />HTTP API<br />HTTP API<br />HTTP API<br />SQL<br />SQL<br />SQL<br />…<br />SQL<br />SQL<br />Solr<br />SQL<br /><ul><li>Separate logical & physical services
  • 25. Easy to tune, easy to maintain, easy to “scale”
  • 26. Stable code, fault-tolerance</li></ul>PRO<br /><ul><li>Higher upfront ops cost
  • 27. Lots of cross-service communication</li></ul>CON<br />
  • 28.
  • 29. www.goliath.io<br /><ul><li>Single responsibility web-services
  • 30. AsyncHTTP response streaming + progressive notifications
  • 31. AsyncHTTP request streaming + progressive notifications
  • 32. Multiple requests within the same VM
  • 33. Keep-alive support
  • 34. Pipelining support
  • 35. Ruby API & “X-Ruby friendly”
  • 36. Easy to maintain & test</li></ul>… lower ops costs<br />… full HTTP 1.1 support<br />… Ruby polyglot!<br />
  • 37. Client API<br />(optional) Fibers<br />optional async<br />“Sync API”<br />Routing<br />Middleware<br />async-rack<br />0.3 ms<br />(streaming) HTTP Parser<br />Ruby, JRuby, Rubinius …<br />HTTP 1.1 <br />EventMachine<br />Network<br />Goliath<br />Optimize bottom up + minimal client API<br />
  • 38. Goliath: Hands on…<br />
  • 39. require'goliath'<br />classHello< Goliath::API<br />defresponse(env)<br /> [200, {}, "Hello World"]<br />end<br />end<br />$>ruby hello.rb-sv –p 8000 –e production<br />Hello World<br />Simple Goliath server<br />
  • 40. classHello< Goliath::API<br /> use Goliath::Rack::Params<br /> use Goliath::Rack::JSONP<br /> use Goliath::Rack::Validation::RequestMethod, %w(GET)<br /> use Goliath::Rack::Validation::RequiredParam, {:key => 'echo'}<br />defresponse(env)<br /> [200, {}, {pong: params['echo’]}]<br />end<br />end<br />Middleware<br />No rackup file<br />
  • 41. classBonjour< Goliath::API<br />defresponse(env)<br /> [200, {}, "bonjour!"]<br />end<br />end<br />classRackRoutes< Goliath::API<br /> map '/version'do<br /> run Proc.new { |env| [200, {}, ["Version 0.1"]] }<br />end<br /> get "/bonjour", Bonjour<br />not_found('/') do<br /># run Proc. new { ... }<br />end<br />end<br />Routing<br />simple, but powerful<br />
  • 42. classAsyncUpload< Goliath::API<br />defon_headers(env, headers)<br />env.logger.info'received headers: '+headers<br />end<br />defon_body(env, data)<br />env.logger.info'received data chunk: '+ data<br />end<br />defon_close(env)<br />env.logger.info'closing connection'<br />end<br />defresponse(env)<br /># called when request processing is complete<br />end<br />end<br />Async Request Processing<br />don’t need to wait for the full request…<br />
  • 43. classStream< Goliath::API<br />defresponse(env)<br />pt=EM.add_periodic_timer(1) { env.stream_send("hello") }<br />EM.add_timer(10) do<br />pt.cancel<br />env.stream_send("goodbye!")<br />env.stream_close<br />end<br />streaming_response 202, {'X-Stream' => 'Goliath’} <br />end<br />end<br />Async/Streaming Response<br />don’t need to render full response…<br />
  • 44. * Goliath::SPDY<br />classWebsocket< Goliath::WebSocket<br />defon_open(env)<br />env.logger.info”WebSocket opened”<br /> end<br />defon_message(env, msg)<br />env.logger.info”WebSocket message: #{msg}”<br /> end<br />defon_close(env)<br />env.logger.info”WebSocket closed”<br /> end<br />defon_error(env, error)<br />env.logger.error error<br />end<br />end<br />Web-Sockets<br />simple backend extension<br />
  • 45. Ruby 1.9: Fibers<br />
  • 46. defresponse(env)<br /> conn =EM::HttpRequest.new(’http://google.com/') <br /> r1 =conn.get :query => {:q => 'gogaruco'}<br /> r1.callback do<br /> r2 =conn.get :query => {:q => 'rubyconf'}<br /> r2.callback { ... }<br /> r2.errback { ... }<br />end<br /> r2.errback { ... }<br />streaming_response 200, {}<br />end<br />Async fun<br />{ { {} } } …<br />
  • 47. defresponse(env)<br /> conn =EM::HttpRequest.new(’http://google.com/') <br /> r1 =conn.get :query => {:q => 'gogaruco'}<br />if r1.error?<br /> r2 =conn.get :query => {:q => 'rubyconf'}<br />else<br /># ...<br />end<br />[200, {}, r2.response]<br />end<br />Async + Fibers<br />Ruby gives us a choice<br />
  • 48. EM-Synchrony:<br />http://github.com/igrigorik/em-synchrony<br /><ul><li>em-http-request
  • 49. em-memcached
  • 50. em-mongo
  • 51. em-jack
  • 52. mysql2
  • 53. redis
  • 54. …
  • 55. ConnectionPool
  • 56. MultiRequest
  • 57. Iterators
  • 58. Inline async
  • 59. TCPSocket
  • 60. …</li></ul>multi =EventMachine::Synchrony::Multi.new<br />multi.add :a, db.aquery("select sleep(1)")<br />multi.add :b, db.aquery("select sleep(1)")<br />res =multi.perform<br />
  • 61. describe HttpLogdo<br /> it 'forwards to our API server'do<br />with_api(HttpLog, api_options) do |api|<br />get_request({}, err) do |c|<br />c.response_header.status.should== 200<br />c.response_header[’X-Header'].should =='Header'<br />c.response.should=='Hello from Responder'<br />end<br />end<br />end<br />end<br />Integration Testing<br />simple end-to-end testing<br />
  • 62. Goliath<br /><ul><li>http://github.com/postrank-labs/goliath
  • 63. http://goliath.io/
  • 64. Google Group: http://groups.google.com/group/goliath-io
  • 65. Examples: GIT repo / examples</li></ul>thoughts, questions?<br />now or later: ilya@igvita.com<br />

×