Goliath ... a tiny GIANT

F. Ros @ Riviera.rb
Frederick Ros

Frederick Ros

Senior Manager, aMaDEUS

Dev addict

twitter@sl33p3r

google++Frederick Ros

Traditional web servers

IO jam

The IO issue

  • L1-cache
    3 cycles
  • L2-cache
    14 cycles
  • RAM
    250 cycles
  • Disk
    41 000 000 cycles
  • Network
    240 000 000 cycles

Enters the Reactor

Single threaded while loop.

Your code reacts to incoming events

Watch out
: do not block the reactor !!


while reactor_running?
  expired_timers.each {|timer| timer.process }
  new_network_io.each {|io| io.process }
end
        

... and EventMachine

Reactor + Async = Event Machine

Spaghetti code !

Writing evented code is hard ... and ugly !

db.find_url { |url|
  http.get(url) { |response|
    email.send(response) {
      puts 'email sent'
    }
  }
}
        

Ruby's Fibers

  • Available on MRI 1.9.x
  • ~ Continuations
  • Light-weigth concurrency: cheaper, easier than threads

fiber = Fiber.new do
  Fiber.yield 1
  2
end

puts fiber.resume # => 1
puts fiber.resume # => 2
puts fiber.resume # => FiberError: dead fiber called
          

EventMachine + Fibers ➪ EM::Synchrony


EventMachine.run {
  page = EventMachine::HttpRequest.new('http://google.com/').get
  page.errback { p "Google is down! terminate?" }
  page.callback {
    about = EventMachine::HttpRequest.new('http://google.com/search?q=eventmachine').get
    about.callback { # callback nesting, ad infinitum }
    about.errback  { # error-handling code }
  }
}
        
▼

EventMachine.synchrony do
  page = EventMachine::HttpRequest.new("http://www.google.com").get
  about = EventMachine::HttpRequest.new('http://google.com/search?q=eventmachine').get
  EventMachine.stop
end
        

Goliath

  • Mix EventMachine and EM::Synchrony
  • Let PostRank iterates on this ...

require 'goliath'

class Hello < Goliath::API
  # default to JSON output, allow Yaml as secondary
  use Goliath::Rack::Render, ['json', 'yaml']

  def response(env)
    [200, {}, "Hello World"]
  end
end

# > ruby hello.rb -sv
# > [97570:INFO] 2011-02-15 00:33:51 :: Starting server on 0.0.0.0:9000 in development mode. Watch out for stones.
        

Goliath

  • App server
  • Fully-asynchronous
  • Streaming support
  • Middleware support
  • Simple configuration
  • High performance: around 3000 req/s
  • Readable and maitainable code

Bonus

  • Middlewares
  • Async Upload
  • Streaming API
  • Routing
  • Websockets
  • Integration testing

Use cases

  • Interface with dbs (present dbs as REST resources)
  • Proxying remote web-services
  • Streaming API
  • Websockets server

Demo time

Stream Twitter search over a websocket !