EM vs Node

EM vs Node

8ddbf811da78bb0daeeb3cacd7cf743f?s=128

Andrew Nesbitt

October 29, 2011
Tweet

Transcript

  1. Is EventMachine a worthy alternative to Node.js

  2. Andrew Nesbitt github.com/andrew @teabass

  3. forwardtechnology.co.uk

  4. Node.js nodejs.org

  5. "Evented I/O for V8 JavaScript" Concurrent, scalable network programs Speaks

    HTTP natively Asynchronous, non-blocking by design
  6. "Realtime" applications Proxy servers Web APIs What would you use

    it for?
  7. Synchronous I/O

  8. Asynchronous I/O

  9. var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}), {'pk':CustomPKFactory});

    p_client.open(function(err, p_client) { p_client.dropDatabase(function(err, done) { p_client.createCollection('test_custom_key', function(err, collection) { collection.insert({'a':1}, function(err, docs) { collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) { cursor.toArray(function(err, items) { test.assertEquals(1, items.length); // Let's close the db p_client.close(); }); }); }); }); }); }); Callback hell gist.github.com/1309020
  10. EventMachine github.com/eventmachine/eventmachine

  11. "Realtime" applications Proxy servers Web APIs What would you use

    it for?
  12. Goliath github.com/postrank-labs/goliath

  13. Rack API Middleware support Ruby fibers No callback hell 1.9.2,

    jruby, rubinius
  14. Fight!

  15. Hello world github.com/andrew/helloworlds

  16. Rack Example class HelloWorld def call(env) [200, {'Content-Type' => 'text/html'},

    ["Hello Rack"]] end end run HelloWorld.new
  17. Node.js Example var http = require('http'); http.createServer(function (req, res) {

    res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello Node\n'); }).listen(9292, "127.0.0.1"); console.log('Server running at http://127.0.0.1:9292/');
  18. EventMachine Example require 'rubygems' require 'eventmachine' require 'evma_httpserver' class HelloWorld

    < EM::Connection include EM::HttpServer def post_init super no_environment_strings end def process_http_request response = EM::DelegatedHttpResponse.new(self) response.status = 200 response.content_type 'text/html' response.content = 'Hello EventMachine' response.send_response end end EM.run{ EM.start_server '0.0.0.0', 9292, HelloWorld }
  19. Goliath Example require 'rubygems' require 'goliath' class Proxy < Goliath::API

    def response(env) [200, {}, "Hello Goliath"] end end
  20. Rack Example class HelloWorld def call(env) [200, {'Content-Type' => 'text/html'},

    ["Hello Rack"]] end end run HelloWorld.new require 'rubygems' require 'goliath' class Proxy < Goliath::API def response(env) [200, {}, "Hello Goliath"] end end
  21. rack => 423 goliath => 2125 node => 6084 em

    => 8814 Performance (requests/s) ab -n 1000 -c 100 http://localhost:9000/
  22. URL Shortener

  23. var http = require('http'), connect = require('connect'), redis = require("redis"),

    client = redis.createClient(), b62 = require('base62'); var server = connect.createServer(connect.query()); server.use('/', connect.router(function(app){ app.get('/', function(req, res, next){ res.writeHead(200, {'Content-Type': 'text/html'}); if (req.query.url){ client.keys('*',function(err, result){ key = b62.encode(result.length) client.set(key, req.query.url, function(err, result){ res.write('http://localhost:9000/'+key) res.end() }); }); } else { res.write('Hi') res.end() } }); app.get('/:key', function(req, res, next){ client.get(req.params.key, function(err, result){ res.writeHead(302, {'Location': result}); res.end() }); }); }) ); server.listen(9000); console.log('Server running at http://127.0.0.1:9000/'); Node Example github.com/andrew/node-shortener
  24. class Shortener < EM::Connection include EM::HttpServer attr_reader :http_request_uri, :http_query_string def

    post_init super no_environment_strings end def process_http_request redis = EM::Protocols::Redis.connect path = @http_request_uri.to_s query = @http_query_string.to_s response = EM::DelegatedHttpResponse.new(self) case path when '/' if @http_query_string params = URI.decode_www_form(query) url = params.assoc('url').last.chomp redis.keys '*' do |result| key = result.size.base62_encode redis.set key, url do |result| response.status = 200 response.content_type 'text/html' response.content = "http://localhost:9000/#{key}" response.send_response end end else response.status = 200 response.content_type 'text/html' response.content = 'Hi' response.send_response end else redis.get path[1..-1] do |result| response.status = 302 response.headers["Location"] = result response.send_response end end end end EM.run{ EM.start_server '0.0.0.0', 9000, Shortener } EM Example github.com/andrew/em-shortener
  25. REDIS = EventMachine::Synchrony::ConnectionPool.new(:size => 5) do Redis.connect end class Redirect

    < Goliath::API use Goliath::Rack::Params def response(env) url = REDIS.get params[:key] if url [302, {:location => url}, nil] else [404, {}, 'Not Found'] end end end class Create < Goliath::API use Goliath::Rack::Params def response(env) if params['url'] key = REDIS.keys.size.base62_encode REDIS.set(key, params['url']) [200, {}, "http://#{env['HTTP_HOST']}/#{key}"] else [200, {}, "Hi!"] end end end class Shortener < Goliath::API map "/" do run Create.new end map "/:key" do run Redirect.new end end Goliath Example github.com/andrew/goliath-shortener
  26. goliath => 1048 node => 3660 em => 7943 Performance

    (requests/s) ab -n 1000 -c 100 http://localhost:9000/2W
  27. Things to consider

  28. Testing

  29. vowsjs.org github.com/tmm1/em-spec Node EM

  30. DSLs

  31. Sinatra get '/hi' do "Hello World!" end sinatrarb.com

  32. Express.js app.get('/', function(req, res){ res.send('Hello World'); }); expressjs.com app.get "/",

    (req, res) -> res.send "Hello World"
  33. class HomeAction < Cramp::Action def start render "Hello World" finish

    end end Cramp cramp.in
  34. Libraries

  35. Deployment

  36. Coffeescript jashkenas.github.com/coffee-script

  37. var http = require('http'), connect = require('connect'), redis = require("redis"),

    client = redis.createClient(), b62 = require('base62'); var server = connect.createServer(connect.query()); server.use('/', connect.router(function(app){ app.get('/', function(req, res, next){ res.writeHead(200, {'Content-Type': 'text/html'}); if (req.query.url){ client.keys('*',function(err, result){ key = b62.encode(result.length) client.set(key, req.query.url, function(err, result){ res.write('http://localhost:9000/'+key) res.end() }); }); } else { res.write('Hi') res.end() } }); app.get('/:key', function(req, res, next){ client.get(req.params.key, function(err, result){ res.writeHead(302, {'Location': result}); res.end() }); }); }) ); server.listen(9000); console.log('Server running at http://127.0.0.1:9000/'); Node Example github.com/andrew/node-shortener
  38. http = require("http") connect = require("connect") redis = require("redis") client

    = redis.createClient() b62 = require("base62") server = connect.createServer(connect.query()) server.use "/", connect.router((app) -> app.get "/", (req, res, next) -> res.writeHead 200, "Content-Type": "text/html" if req.query.url client.keys "*", (err, result) -> key = b62.encode(result.length) client.set key, req.query.url, (err, result) -> res.write "http://localhost:9000/" + key res.end() else res.write "Hi" res.end() app.get "/:key", (req, res, next) -> client.get req.params.key, (err, result) -> res.writeHead 302, Location: result res.end() ) server.listen 9000 console.log "Server running at http://127.0.0.1:9000/" Coffeescript Example
  39. Rails

  40. async-rails github.com/igrigorik/async-rails

  41. Conclusion

  42. Node Pros Shared code between client and server Vibrant Community

    Lightning Fast Cons Javascript Callback hell Less mature
  43. EventMachine Pros It’s ruby! Mature Clever DSLs Also fast Cons

    More difficult to write than normal ruby Restricted to EM libraries Not the new hotness
  44. Is EventMachine a worthy alternative to Node.js

  45. Yes

  46. Node or EM are not a magic bullets

  47. Go - http://golang.org/ Erlang - http://erlang.org/ Twisted - http://twistedmatrix.com Other

    languages
  48. Fin. speakerdeck.com/u/andrew/p/em-vs-node