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

  • 45,551 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
45,551
On Slideshare
0
From Embeds
0
Number of Embeds
15

Actions

Shares
Downloads
68
Comments
0
Likes
21

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
    building high-performance (Ruby) web services
    Ilya Grigorik
    @igrigorik
  • 2. conn =EM::HttpRequest.new('http://gogaruco.com')
    r1 =conn.get :path => "speakers.html", :keepalive => true# 250 ms
    r2 =conn.get :path => "schedule.html"# 300 ms
    # wait until done …
    Answer:
    All of the above!
    Total execution time is:
    250 ms
    300 ms
    550 ms
    ~ 65% truthiness
    ~ 25% truthiness *
    ~ 10% truthiness **
    HTTP Quiz
    this is not a trick question…
  • 3. “SPDY? We can’t even get HTTP right…”
    the why, how, and how-to of Goliath
  • 4. Server
    Client
    20 ms
    TCP handshake
    HTTP Request
    • headers, body
    40 ms
    processing
    Multi-part body (*)
    Terminate connection
    HTTP 1.0
    RFC 1945 (1996)
    + 40ms TCP setup (network)
    + 20ms request (network)
    + 40ms processing
    + 20ms response (network)
    66% of time in network overhead
  • 5. Benchmark client RTT, not just the server processing time
    A public service announcement…
  • 6. Keep-alive
    • Re-use open connection
    • 7. No multiplexing, serial
    • 8. Default to “on”
    Pipelining
    • No multiplexing
    • 9. Parallel requests
    HTTP 1.1
    RFC 2616 (1999)
  • 10. + 40ms TCP setup (network)
    + 20ms request (network)
    + 40ms processing
    + 20ms response (network)
    x 40ms TCP setup (network)
    + 20ms request (network)
    + 40ms processing
    + 20ms response (network)
    200ms for two requests
    Small win over HTTP 1.0
    Keep-alive
    RFC 2616 (1999)
    * One gotcha…
  • 11. Net:HTTP
    Keep-alive
    RFC 2616 (1999)
    Connection: close < ugh!
  • 12. + 40ms TCP setup (network)
    + 20ms request (network)
    + 40ms processing
    + 20ms response (network)
    60% of time in network overhead
    120ms for two requests – 50% improvement!
    Pipelining
    RFC 2616 (1999)
  • 13. Connection setup: 50ms
    Request 1: 300ms
    Request 2: 250ms
    Total time:
    ~250 ms
    ~300 ms
    ~350 ms
    ~600 ms
    Pipelining Quiz
    RFC 2616 (1999)
  • 14. There is just one small gotcha…
    Making HTTP Pipelining Usable on the Open Web
    http://tools.ietf.org/html/draft-nottingham-http-pipeline-01
  • 15. conn =EM::HttpRequest.new('http://gogaruco.com')
    r1 =conn.get :path => "speakers.html", :keepalive => true# 250 ms
    r2 =conn.get :path => "schedule.html"# 300 ms
    Total execution time is:
    250 ms
    300 ms
    550 ms
    Keep-alive what? HTTP 1.0!
    ~ 65% truthiness
    ~ 25% truthiness *
    ~ 10% truthiness **
    Good: Keep-alive + Pipelining
    Bad: Keep-alive + Garbage
    “I’m confused”
    HTTP in the wild
    it’s a sad state of affairs
    Keep-alive: mostly works – yay!
    Pipelining: disabled (except in Opera)
  • 16. HTTP can be a high-performance transport
    Goliath is our attempt to make it work
  • 17.
    • 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
    +
    +
    Brief History
    Goliath @ PostRank
  • 24. Rails

    HTTP API
    HTTP API
    HTTP API
    HTTP API
    SQL
    SQL
    SQL

    SQL
    SQL
    Solr
    SQL
    • Separate logical & physical services
    • 25. Easy to tune, easy to maintain, easy to “scale”
    • 26. Stable code, fault-tolerance
    PRO
    • Higher upfront ops cost
    • 27. Lots of cross-service communication
    CON
  • 28.
  • 29. www.goliath.io
    • 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
    … lower ops costs
    … full HTTP 1.1 support
    … Ruby polyglot!
  • 37. Client API
    (optional) Fibers
    optional async
    “Sync API”
    Routing
    Middleware
    async-rack
    0.3 ms
    (streaming) HTTP Parser
    Ruby, JRuby, Rubinius …
    HTTP 1.1
    EventMachine
    Network
    Goliath
    Optimize bottom up + minimal client API
  • 38. Goliath: Hands on…
  • 39. require'goliath'
    classHello< Goliath::API
    defresponse(env)
    [200, {}, "Hello World"]
    end
    end
    $>ruby hello.rb-sv –p 8000 –e production
    Hello World
    Simple Goliath server
  • 40. classHello< Goliath::API
    use Goliath::Rack::Params
    use Goliath::Rack::JSONP
    use Goliath::Rack::Validation::RequestMethod, %w(GET)
    use Goliath::Rack::Validation::RequiredParam, {:key => 'echo'}
    defresponse(env)
    [200, {}, {pong: params['echo’]}]
    end
    end
    Middleware
    No rackup file
  • 41. classBonjour< Goliath::API
    defresponse(env)
    [200, {}, "bonjour!"]
    end
    end
    classRackRoutes< Goliath::API
    map '/version'do
    run Proc.new { |env| [200, {}, ["Version 0.1"]] }
    end
    get "/bonjour", Bonjour
    not_found('/') do
    # run Proc. new { ... }
    end
    end
    Routing
    simple, but powerful
  • 42. classAsyncUpload< Goliath::API
    defon_headers(env, headers)
    env.logger.info'received headers: '+headers
    end
    defon_body(env, data)
    env.logger.info'received data chunk: '+ data
    end
    defon_close(env)
    env.logger.info'closing connection'
    end
    defresponse(env)
    # called when request processing is complete
    end
    end
    Async Request Processing
    don’t need to wait for the full request…
  • 43. classStream< Goliath::API
    defresponse(env)
    pt=EM.add_periodic_timer(1) { env.stream_send("hello") }
    EM.add_timer(10) do
    pt.cancel
    env.stream_send("goodbye!")
    env.stream_close
    end
    streaming_response 202, {'X-Stream' => 'Goliath’}
    end
    end
    Async/Streaming Response
    don’t need to render full response…
  • 44. * Goliath::SPDY
    classWebsocket< Goliath::WebSocket
    defon_open(env)
    env.logger.info”WebSocket opened”
    end
    defon_message(env, msg)
    env.logger.info”WebSocket message: #{msg}”
    end
    defon_close(env)
    env.logger.info”WebSocket closed”
    end
    defon_error(env, error)
    env.logger.error error
    end
    end
    Web-Sockets
    simple backend extension
  • 45. Ruby 1.9: Fibers
  • 46. defresponse(env)
    conn =EM::HttpRequest.new(’http://google.com/')
    r1 =conn.get :query => {:q => 'gogaruco'}
    r1.callback do
    r2 =conn.get :query => {:q => 'rubyconf'}
    r2.callback { ... }
    r2.errback { ... }
    end
    r2.errback { ... }
    streaming_response 200, {}
    end
    Async fun
    { { {} } } …
  • 47. defresponse(env)
    conn =EM::HttpRequest.new(’http://google.com/')
    r1 =conn.get :query => {:q => 'gogaruco'}
    if r1.error?
    r2 =conn.get :query => {:q => 'rubyconf'}
    else
    # ...
    end
    [200, {}, r2.response]
    end
    Async + Fibers
    Ruby gives us a choice
  • 48. EM-Synchrony:
    http://github.com/igrigorik/em-synchrony
    multi =EventMachine::Synchrony::Multi.new
    multi.add :a, db.aquery("select sleep(1)")
    multi.add :b, db.aquery("select sleep(1)")
    res =multi.perform
  • 61. describe HttpLogdo
    it 'forwards to our API server'do
    with_api(HttpLog, api_options) do |api|
    get_request({}, err) do |c|
    c.response_header.status.should== 200
    c.response_header[’X-Header'].should =='Header'
    c.response.should=='Hello from Responder'
    end
    end
    end
    end
    Integration Testing
    simple end-to-end testing
  • 62. Goliath
    • 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
    thoughts, questions?
    now or later: ilya@igvita.com