Upgrade to Pro — share decks privately, control downloads, hide ads and more …

EM vs Node

EM vs Node

Andrew Nesbitt

October 29, 2011
Tweet

More Decks by Andrew Nesbitt

Other Decks in Technology

Transcript

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

    HTTP natively Asynchronous, non-blocking by design
  2. 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
  3. 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/');
  4. 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 }
  5. Goliath Example require 'rubygems' require 'goliath' class Proxy < Goliath::API

    def response(env) [200, {}, "Hello Goliath"] end end
  6. 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
  7. rack => 423 goliath => 2125 node => 6084 em

    => 8814 Performance (requests/s) ab -n 1000 -c 100 http://localhost:9000/
  8. 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
  9. 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
  10. 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
  11. goliath => 1048 node => 3660 em => 7943 Performance

    (requests/s) ab -n 1000 -c 100 http://localhost:9000/2W
  12. 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
  13. 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
  14. Node Pros Shared code between client and server Vibrant Community

    Lightning Fast Cons Javascript Callback hell Less mature
  15. 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
  16. Yes