SlideShare a Scribd company logo
1 of 199
Download to read offline
“ Genius is the gold in the mine; talent is
  the miner who works and brings it out. ”
 Lady Marguerite Blessington




                                        Donets Basin
                                        Coal Mine-Ukraine
“ Genius is the gold in the mine; talent is
  the miner who works and brings it out. ”
 Lady Marguerite Blessington




         Презентация начнется в
       течение нескольких минут ...


                                        Donets Basin
                                        Coal Mine-Ukraine
доброе утро
Fabio Akita, Co-Founder @CodeMiner42
“Off-centered software for
      off-centered people”
       Fabio Akita, Co-Founder @CodeMiner42
Toster - Understanding the Rails Web Model and Scalability Options
Toster - Understanding the Rails Web Model and Scalability Options
Understanding
the Rails Web Model
and Scalability Options
?
Toster - Understanding the Rails Web Model and Scalability Options
Toster - Understanding the Rails Web Model and Scalability Options
rails new app
Toster - Understanding the Rails Web Model and Scalability Options
somethings don’t change
Toster - Understanding the Rails Web Model and Scalability Options
CGI
1 request blocks 1 process
require 'rubygems'
require 'rack'

class Test
  def call(env)

    sleep 1 # on purpose, simulating a blocking operation

    [200, {"Content-Type" => "text/plain"},
      ["Hello World!"]]
  end
end

Rack::Handler::Thin.run Test.new
require 'rubygems'
require 'rack'

class Test
  def call(env)

    sleep 1 # on purpose, simulating a blocking operation

    [200, {"Content-Type" => "text/plain"},
      ["Hello World!"]]
  end
end

Rack::Handler::Thin.run Test.new
$ rackup config.ru

>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:8080, CTRL+C to stop
ab -n 10 -c 1 http://127.0.0.1:8080/

This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      1
Time taken for tests:   10.020 seconds
...
Requests per second:    1.00 [#/sec] (mean)
Time per request:       1002.015 [ms] (mean)
Time per request:       1002.015 [ms] (mean, across all concurrent requests)
Transfer rate:          0.12 [Kbytes/sec] received
...
ab -n 10 -c 1 http://127.0.0.1:8080/

This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      1
Time taken for tests:   10.020 seconds
...
Requests per second:    1.00 [#/sec] (mean)
Time per request:       1002.015 [ms] (mean)
Time per request:       1002.015 [ms] (mean, across all concurrent requests)
Transfer rate:          0.12 [Kbytes/sec] received
...
ab -n 10 -c 1 http://127.0.0.1:8080/

This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      1
Time taken for tests:   10.020 seconds
...
Requests per second:    1.00 [#/sec] (mean)
Time per request:       1002.015 [ms] (mean)
Time per request:       1002.015 [ms] (mean, across all concurrent requests)
Transfer rate:          0.12 [Kbytes/sec] received
...
ab -n 10 -c 1 http://127.0.0.1:8080/

This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      1
Time taken for tests:   10.020 seconds
...
Requests per second:    1.00 [#/sec] (mean)
Time per request:       1002.015 [ms] (mean)
Time per request:       1002.015 [ms] (mean, across all concurrent requests)
Transfer rate:          0.12 [Kbytes/sec] received
...
ab -n 10 -c 1 http://127.0.0.1:8080/

This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      1
Time taken for tests:   10.020 seconds
...
Requests per second:    1.00 [#/sec] (mean)
Time per request:       1002.015 [ms] (mean)
Time per request:       1002.015 [ms] (mean, across all concurrent requests)
Transfer rate:          0.12 [Kbytes/sec] received
...
Browser   Browser   Browser   Browser    Browser   Browser




                     NginX, HAProxy


                    Passenger, Unicorn
Optimize
Browser    Browser   Browser    Browser   Browser      Browser




                       NginX, HAProxy


          Passenger, Unicorn (CoW GC - REE or MRI 2)
Toster - Understanding the Rails Web Model and Scalability Options
Ruby Enterprise Edition 1.8.7    Copy on Write patched
 (about to be deprecated)         mark and sweep GC



    Ruby 1.9.2 (current)          mark and sweep GC



 Ruby 1.9.3 (transitioning)         Lazy Sweep GC



                                Copy on Write compatible
     Ruby 2.0 (future)
                                   Bitmap Marking GC
Ruby Enterprise Edition 1.8.7    Copy on Write patched
 (about to be deprecated)         mark and sweep GC



    Ruby 1.9.2 (current)          mark and sweep GC



 Ruby 1.9.3 (transitioning)         Lazy Sweep GC



                                Copy on Write compatible
     Ruby 2.0 (future)
                                   Bitmap Marking GC
Ruby Enterprise Edition 1.8.7    Copy on Write patched
 (about to be deprecated)         mark and sweep GC



    Ruby 1.9.2 (current)          mark and sweep GC



 Ruby 1.9.3 (transitioning)         Lazy Sweep GC



                                Copy on Write compatible
     Ruby 2.0 (future)
                                   Bitmap Marking GC
Ruby Enterprise Edition 1.8.7    Copy on Write patched
 (about to be deprecated)         mark and sweep GC



    Ruby 1.9.2 (current)          mark and sweep GC



 Ruby 1.9.3 (transitioning)         Lazy Sweep GC



                                Copy on Write compatible
     Ruby 2.0 (future)
                                   Bitmap Marking GC
Browser   Browser   Browser    Browser




           NginX, HAProxy

          Passenger, Unicorn
Browser   Browser   Browser    Browser




           NginX, HAProxy

          Passenger, Unicorn




             Memcached
Browser   Browser   Browser    Browser



               Varnish

           NginX, HAProxy

          Passenger, Unicorn




             Memcached
Browser   Browser   Browser    Browser



               Varnish

           NginX, HAProxy

          Passenger, Unicorn


                                         Resque


             Memcached
Browser   Browser   Browser    Browser



               Varnish

           NginX, HAProxy

          Passenger, Unicorn


                                         Resque


             Memcached
Too Long or
Periodic Polling
Toster - Understanding the Rails Web Model and Scalability Options
Notifications and Events in general


         Online Gaming


     Chatting and Presence


    Collaborative Applications


Advanced and more Interactive UI
(function poll(){

        $.ajax({ url: "server", success: function(data){
          // do something with the received ‘data’

          //Setup the next poll recursively
          poll();
        }, dataType: "json"});

})();
(function poll(){
   setTimeout(function(){
      $.ajax({ url: "server", success: function(data){
        // do something with the received ‘data’

        //Setup the next poll recursively
        poll();
      }, dataType: "json"});
  }, 5000);
})();
Toster - Understanding the Rails Web Model and Scalability Options
Cross Frame communication


          HTTP Polling (Ajax)


Liveconnect (Java applets, Flash socket)


             Long Polling


       Comet & HTTP Streaming
 (ex. forever frame/chunked encode)
Toster - Understanding the Rails Web Model and Scalability Options
Toster - Understanding the Rails Web Model and Scalability Options
W3C/IETF Standard - RFC 6455
                (12/2011)


Full duplex persistent communication channel


         Less overhead than HTTP
        (down to 2 bytes per frame)

       No latency (no reconnections)
      No polling overhead (on demand)

        “Upgrades” HTTP, uses 80/443
     (kind of friendly to existing proxies)
<script type="text/javascript">
  var ws = new WebSocket("ws://example.com:10081/");




</script>
<script type="text/javascript">
  var ws = new WebSocket("ws://example.com:10081/");

  ws.onopen = function() {
     ws.send("Hello"); // Sends a message.
  };

  ws.onmessage = function(e) {
     // Receives a message.
     alert(e.data);
  };

  ws.onclose = function() {
     alert("closed");
  };
</script>
Toster - Understanding the Rails Web Model and Scalability Options
Protocol        IE       Firefox      Chrome   Safari    Opera

hixie-75                                4        5

 hixie-76                    4          6       5.0.1       11
 hybi-00                 (disabled)                     (disabled)

hybi-06     HTML5 Labs     dev

hybi-07                      6

hybi-09     HTML5 Labs

hybi-10        IE 10         7          14

RFC 6455                     11         16
POLYFILL/FALLBACK
     (web-socket-js)
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript" src="web_socket.js"></script>
<script type="text/javascript">
  // Let the library know where WebSocketMain.swf is:
  WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf";

  var ws = new WebSocket("ws://example.com:10081/");
  ws.onopen = function() {
     ws.send("Hello"); // Sends a message.
  };
  ws.onmessage = function(e) {
     // Receives a message.
     alert(e.data);
  };
  ws.onclose = function() {
     alert("closed");
  };
</script>
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript" src="web_socket.js"></script>
<script type="text/javascript">
  // Let the library know where WebSocketMain.swf is:
  WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf";

  var ws = new WebSocket("ws://example.com:10081/");
  ws.onopen = function() {
     ws.send("Hello"); // Sends a message.
  };
  ws.onmessage = function(e) {
     // Receives a message.
     alert(e.data);
  };
  ws.onclose = function() {
     alert("closed");
  };
</script>
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript" src="web_socket.js"></script>
<script type="text/javascript">
  // Let the library know where WebSocketMain.swf is:
  WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf";

  var ws = new WebSocket("ws://example.com:10081/");
  ws.onopen = function() {
     ws.send("Hello"); // Sends a message.
  };
  ws.onmessage = function(e) {
     // Receives a message.
     alert(e.data);
  };
  ws.onclose = function() {
     alert("closed");
  };
</script>
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript" src="web_socket.js"></script>
<script type="text/javascript">
  // Let the library know where WebSocketMain.swf is:
  WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf";

  var ws = new WebSocket("ws://example.com:10081/");
  ws.onopen = function() {
     ws.send("Hello"); // Sends a message.
  };
  ws.onmessage = function(e) {
     // Receives a message.
     alert(e.data);
  };
  ws.onclose = function() {
     alert("closed");
  };
</script>
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript" src="web_socket.js"></script>
<script type="text/javascript">
  // Let the library know where WebSocketMain.swf is:
  WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf";

  var ws = new WebSocket("ws://example.com:10081/");
  ws.onopen = function() {
     ws.send("Hello"); // Sends a message.
  };
  ws.onmessage = function(e) {
     // Receives a message.
     alert(e.data);
  };
  ws.onclose = function() {
     alert("closed");
  };
</script>
Client: kind of OK
Server: what do do?
Long running requests
Reactor Pattern
   (Eventmachine)
Toster - Understanding the Rails Web Model and Scalability Options
synchronous I/O



non-blocking synchronous I/O



non-blocking asynchronous I/0
Wait Events
                (I/O, timers)




  Main Loop          Notifies Event
(main thread)          Handlers
Toster - Understanding the Rails Web Model and Scalability Options
select   poll
select   poll   epoll   kqueue   IOCP
libevent          libev


select       poll   epoll   kqueue   IOCP
Tornado


  Twisted


  libevent          libev


select       poll   epoll   kqueue   IOCP
Tornado


  Twisted           Node.js


  libevent           libev


select       poll    epoll    kqueue   IOCP
Tornado           Cool.io


  Twisted           Node.js


  libevent           libev


select       poll    epoll    kqueue   IOCP
Tornado           Cool.io


  Twisted           Node.js


  libevent           libev        EventMachine


select       poll    epoll    kqueue     IOCP
Tornado           Cool.io            Goliath


  Twisted           Node.js             Thin


  libevent           libev        EventMachine


select       poll    epoll    kqueue       IOCP
require 'rubygems'
require 'rack'

class Test
  def call(env)

    sleep 1 # on purpose, simulating a blocking operation

    [200, {"Content-Type" => "text/plain"},
      ["Hello World!"]]
  end
end

Rack::Handler::Thin.run Test.new
require 'rubygems'
require 'rack'

class Test
  def call(env)
    EM.defer do
      sleep 1 # CPU bound, throw to thread-pool (cheating)
    end
    [200, {"Content-Type" => "text/plain"},
      ["Hello World!"]]
  end
end

Rack::Handler::Thin.run Test.new
require 'rubygems'
require 'rack'

class Test
  def call(env)
    EM.defer do
      sleep 1 # CPU bound, throw to thread-pool (cheating)
    end
    [200, {"Content-Type" => "text/plain"},
      ["Hello World!"]]
  end
end

Rack::Handler::Thin.run Test.new
require 'rubygems'
require 'rack'

class Test
  def call(env)
    EM.defer do
      sleep 1 # CPU bound, throw to thread-pool (cheating)
    end
    [200, {"Content-Type" => "text/plain"},
      ["Hello World!"]]
  end
end

Rack::Handler::Thin.run Test.new
ab -n 10 -c 1 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      1
Time taken for tests:   0.003 seconds
...
Requests per second:    3219.58 [#/sec] (mean)
Time per request:       0.311 [ms] (mean)
Time per request:       0.311 [ms] (mean, across all concurrent requests)
Transfer rate:          380.44 [Kbytes/sec] received
...
ab -n 10 -c 1 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      1
Time taken for tests:   0.003 seconds
...
Requests per second:    3219.58 [#/sec] (mean)
Time per request:       0.311 [ms] (mean)
Time per request:       0.311 [ms] (mean, across all concurrent requests)
Transfer rate:          380.44 [Kbytes/sec] received
...
ab -n 10 -c 1 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      1
Time taken for tests:   0.003 seconds
...
Requests per second:    3219.58 [#/sec] (mean)
Time per request:       0.311 [ms] (mean)
Time per request:       0.311 [ms] (mean, across all concurrent requests)
Transfer rate:          380.44 [Kbytes/sec] received
...
ab -n 10 -c 1 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      1
Time taken for tests:   0.003 seconds
...
Requests per second:    3219.58 [#/sec] (mean)
Time per request:       0.311 [ms] (mean)
Time per request:       0.311 [ms] (mean, across all concurrent requests)
Transfer rate:          380.44 [Kbytes/sec] received
...
ab -n 10 -c 1 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      1
Time taken for tests:   0.003 seconds
...
Requests per second:    3219.58 [#/sec] (mean)
Time per request:       0.311 [ms] (mean)
Time per request:       0.311 [ms] (mean, across all concurrent requests)
Transfer rate:          380.44 [Kbytes/sec] received
...
ab -n 10 -c 1 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1178079 $>

                                                          #ZOMG!
...
Concurrency Level:      1
Time taken for tests:   0.003 seconds
...
Requests per second:    3219.58 [#/sec] (mean)
Time per request:       0.311 [ms] (mean)
Time per request:       0.311 [ms] (mean, across all concurrent requests)
Transfer rate:          380.44 [Kbytes/sec] received
...
ab -n 10 -c 10 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      10
Time taken for tests:   0.002 seconds
...
Requests per second:    5211.05 [#/sec] (mean)
Time per request:       1.919 [ms] (mean)
Time per request:       0.192 [ms] (mean, across all concurrent requests)
Transfer rate:          615.76 [Kbytes/sec] received
...
Toster - Understanding the Rails Web Model and Scalability Options
Block     Non-Block



 Total Time    10 sec   0.0001 sec

Requests per
  Second         1       + 8000
Block     Non-Block



 Total Time    10 sec   0.0001 sec

Requests per
  Second         1       + 8000
Block     Non-Block



 Total Time    10 sec   0.0001 sec

Requests per
  Second         1       + 8000
“Tick”
                      Timers
                    #add_timer
                 #add_periodic_timer




 Reactor Loop            Blocking Tasks
(Eventmachine)               #defer
                           #next_tick
require 'rubygems' # or use Bundler.setup
require 'eventmachine'

class EchoServer < EM::Connection
  def receive_data(data)
    if data.strip =~ /[exit|quit]$/i
      EM.stop
    else
      send_data("Repeating: #{data}")
    end
  end
end
require 'rubygems' # or use Bundler.setup
require 'eventmachine'

class EchoServer < EM::Connection
  def receive_data(data)
    if data.strip =~ /[exit|quit]$/i
      EM.stop
    else
      send_data("Repeating: #{data}")
    end
  end
end

EventMachine.run do
  # hit Control + C to stop
  Signal.trap("INT") { EM.stop }
  Signal.trap("TERM") { EM.stop }

  EM.start_server("0.0.0.0", 10000, EchoServer)
end
$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello World
$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello World
Repeating: Hello World
$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello World
Repeating: Hello World
Play again, Sam
$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello World
Repeating: Hello World
Play again, Sam
Repeating: Play again, Sam
$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello World
Repeating: Hello World
Play again, Sam
Repeating: Play again, Sam
quit
.
$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello World
Repeating: Hello World
Play again, Sam
Repeating: Play again, Sam
quit
Connection closed by foreign host.
require 'rubygems'
require 'eventmachine'

EM.run do
  # ... main reactor loop
  EM.stop # stop the main loop and exit
end
require 'rubygems'
require 'eventmachine'

EM.run   do
  puts   1
  puts   2
  puts   3
end
$ ruby em.rb
1
2
3
require 'rubygems'
require 'eventmachine'

EM.run do
  EM.defer do
    sleep 3
    puts 1
  end

  EM.add_timer(1) do
    puts 2

    EM.add_timer(1) do
      puts 3
    end
  end

  puts 4
end
$ ruby em.rb
4
2
3
1
Toster - Understanding the Rails Web Model and Scalability Options
var http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World');
}).listen(9876);
ab -n 1000 -c 5 http://127.0.0.1:9876/
This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      5
Time taken for tests:   0.124 seconds
...
Requests per second:    8035.36 [#/sec] (mean)
Time per request:       0.622 [ms] (mean)
Time per request:       0.124 [ms] (mean, across all concurrent requests)
Transfer rate:          588.53 [Kbytes/sec] received
...
require 'rubygems'
require 'rack'

Rack::Handler::Thin.run Proc.new {
  [200, {"Content-Type" => "text/plain"}, ["Hello World!"]]
}
ab -n 1000 -c 5 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1178079 $>
...
Concurrency Level:      5
Time taken for tests:   0.121 seconds
..
Requests per second:    8239.06 [#/sec] (mean)
Time per request:       0.607 [ms] (mean)
Time per request:       0.121 [ms] (mean, across all concurrent requests)
Transfer rate:          973.56 [Kbytes/sec] received
...
Toster - Understanding the Rails Web Model and Scalability Options
Node.js                     Ruby


        libev             Eventmachine, Cool.io


      Google V8            MRI, JRuby, Rubinius


Less Resources, Faster   More Resources, Slightly
      Processing           slower processing


    callbacks only       Threads, Fibers, Callbacks
Node.js                     Ruby


        libev             Eventmachine, Cool.io


      Google V8            MRI, JRuby, Rubinius


Less Resources, Faster   More Resources, Slightly
      Processing           slower processing


    callbacks only       Threads, Fibers, Callbacks
Node.js                     Ruby


        libev             Eventmachine, Cool.io


      Google V8            MRI, JRuby, Rubinius


Less Resources, Faster   More Resources, Slightly
      Processing           slower processing


    callbacks only       Threads, Fibers, Callbacks
Node.js                     Ruby


        libev             Eventmachine, Cool.io


      Google V8            MRI, JRuby, Rubinius


Less Resources, Faster   More Resources, Slightly
      Processing           slower processing


    callbacks only       Threads, Fibers, Callbacks
Node.js                     Ruby


        libev             Eventmachine, Cool.io


      Google V8            MRI, JRuby, Rubinius


Less Resources, Faster   More Resources, Slightly
      Processing           slower processing


    callbacks only       Threads, Fibers, Callbacks
EM-Websocket
require "rubygems"
require 'eventmachine'
require 'em-websocket'

config = {:host => "0.0.0.0", :port => 8080, :debug => true}
EM::WebSocket.start(config) do |ws|
  ws.onopen    { ws.send "Welcome!"}
  ws.onmessage { |msg| ws.send "Sending Pong: #{msg}" }
  ws.onclose   { puts "connection closed" }
  ws.onerror   { |e| puts "Error: #{e.message}" }
end
Caveats in Callback Driven
     Development
fs.rename('/tmp/hello', '/tmp/world', function (err) {
  if (err) throw err;
  console.log('renamed complete');
});

fs.stat('/tmp/world', function (err, stats) {
  if (err) throw err;
  console.log('stats: ' + JSON.stringify(stats));
});
fs.rename('/tmp/hello', '/tmp/world', function (err) {
  if (err) throw err;
  fs.stat('/tmp/world', function (err, stats) {
    if (err) throw err;
    console.log('stats: ' + JSON.stringify(stats));
  });
});
EM.run do
  page = EM::HttpRequest.new(@url1).get
  page.errback do
    puts "Site is down! terminate?"
  end
  page.callback do
    about = EM::HttpRequest.new(@url2).get
    about.callback do
      # callback nesting, ad infinitum
    end
    about.errback do
      # error-handling code
    end
  end
end
“Callback Spaghetti”
Ruby 1.9 Fibers
to the rescue!
number_generator = Fiber.new do
  start = 0
  loop do
    start += 1
    Fiber.yield(start)
  end
end
number_generator = Fiber.new do
  start = 0
  loop do
    start += 1
    Fiber.yield(start)
  end
end

> number_generator.resume
 => 1
number_generator = Fiber.new do
  start = 0
  loop do
    start += 1
    Fiber.yield(start)
  end
end

> number_generator.resume
 => 1
> number_generator.resume
 => 2
number_generator = Fiber.new do
  start = 0
  loop do
    start += 1
    Fiber.yield(start)
  end
end

> number_generator.resume
 => 1
> number_generator.resume
 => 2
> number_generator.resume
 => 3
Toster - Understanding the Rails Web Model and Scalability Options
Less expensive than Threads


      cooperative vs preemptive multitasking


          developer controls scheduling


     no need to have mutexes, no shared data


coroutines / can be implemented with continuations
Less expensive than Threads


      cooperative vs preemptive multitasking


          developer controls scheduling


     no need to have mutexes, no shared data


coroutines / can be implemented with continuations
Less expensive than Threads


      cooperative vs preemptive multitasking


          developer controls scheduling


     no need to have mutexes, no shared data


coroutines / can be implemented with continuations
Less expensive than Threads


      cooperative vs preemptive multitasking


          developer controls scheduling


     no need to have mutexes, no shared data


coroutines / can be implemented with continuations
Less expensive than Threads


      cooperative vs preemptive multitasking


          developer controls scheduling


     no need to have mutexes, no shared data


coroutines / can be implemented with continuations
EM.run do
  page = EM::HttpRequest.new(@url1).get
  page.errback do
    puts "Site is down! terminate?"
  end
  page.callback do
    about = EM::HttpRequest.new(@url2).get
    about.callback do
      # callback nesting, ad infinitum
    end
    about.errback do
      # error-handling code
    end
  end
end
page = http_get(@url1)
puts "Fetched page: #{page.response_header.status}"
if page
  page = http_get(@url2)
  puts "Fetched page 2: #{page.response_header.status}"
end
def http_get(url)
  f = Fiber.current
  http = EM::HttpRequest.new(url).get
  http.callback{ f.resume(http) }
  http.errback { f.resume(http) }
  return Fiber.yield
end

EM.run do
  Fiber.new do
    page = http_get(@url1)
    puts "Fetched page: #{page.response_header.status}"
    if page
      page = http_get(@url2)
      puts "Fetched page 2: #{page.response_header.status}"
    end
  do.resume
end
def http_get(url)
  f = Fiber.current
  http = EM::HttpRequest.new(url).get
  http.callback{ f.resume(http) }
  http.errback { f.resume(http) }
  return Fiber.yield
end

EM.run do
  Fiber.new do
    page = http_get(@url1)
    puts "Fetched page: #{page.response_header.status}"
    if page
      page = http_get(@url2)
      puts "Fetched page 2: #{page.response_header.status}"
    end
  do.resume
end
def http_get(url)
  f = Fiber.current
  http = EM::HttpRequest.new(url).get
  http.callback{ f.resume(http) }
  http.errback { f.resume(http) }
  return Fiber.yield
end

EM.run do
  Fiber.new do
    page = http_get(@url1)
    puts "Fetched page: #{page.response_header.status}"
    if page
      page = http_get(@url2)
      puts "Fetched page 2: #{page.response_header.status}"
    end
  do.resume
end
def http_get(url)
  f = Fiber.current
  http = EM::HttpRequest.new(url).get
  http.callback{ f.resume(http) }
  http.errback { f.resume(http) }
  return Fiber.yield
end

EM.run do
  Fiber.new do
    page = http_get(@url1)
    puts "Fetched page: #{page.response_header.status}"
    if page
      page = http_get(@url2)
      puts "Fetched page 2: #{page.response_header.status}"
    end
  do.resume
end
def http_get(url)
  f = Fiber.current
  http = EM::HttpRequest.new(url).get
  http.callback{ f.resume(http) }
  http.errback { f.resume(http) }
  return Fiber.yield
end

EM.run do
  Fiber.new do
    page = http_get(@url1)
    puts "Fetched page: #{page.response_header.status}"
    if page
      page = http_get(@url2)
      puts "Fetched page 2: #{page.response_header.status}"
    end
  do.resume
end
def http_get(url)
  f = Fiber.current
  http = EM::HttpRequest.new(url).get
  http.callback{ f.resume(http) }
  http.errback { f.resume(http) }
  return Fiber.yield
end

EM.run do
  Fiber.new do
    page = http_get(@url1)
    puts "Fetched page: #{page.response_header.status}"
    if page
      page = http_get(@url2)
      puts "Fetched page 2: #{page.response_header.status}"
    end
  do.resume
end
def http_get(url)
  f = Fiber.current
  http = EM::HttpRequest.new(url).get
  http.callback{ f.resume(http) }
  http.errback { f.resume(http) }
  return Fiber.yield
end

EM.run do
  Fiber.new do
    page = http_get(@url1)
    puts "Fetched page: #{page.response_header.status}"
    if page
      page = http_get(@url2)
      puts "Fetched page 2: #{page.response_header.status}"
    end
  do.resume
end
EM-Synchrony
EM.synchrony do
  page = EM::HttpRequest.new("http://www.google.com").get
  puts "Look Ma! No callbacks! Fetched page: #{page}"
  EM.stop
end

# old way
EM.run do
  page = EM::HttpRequest.new("http://www.google.com").get
  page.callback do
    puts "Lame ... Fetched page: #{page}"
    EM.stop
  end
end
Goliath
require 'goliath'
require 'yajl'

G = Goliath::Rack # don’t to this, just to fit in this slide :-)
class Echo < Goliath::API
  use G::Render, 'json' # auto-negotiate response format
  use G::Params         # parse & merge query and body parameters
  use G::Validation::RequiredParam, {:key => 'echo'}

  def process_request
    logger.info "Processing request"
    {response: env.params['echo']}
  end

  def response(env)
    [200, {}, process_request]
  end
end
$ ruby echo.rb -p 9001
$ ruby echo.rb -p 9001

$ curl http://localhost:9001/
{"error":"Echo identifier missing"}
$ ruby echo.rb -p 9001

$ curl http://localhost:9001/
{"error":"Echo identifier missing"}

$ curl http://localhost:9001?echo=Hello%20World
{"response":"Hello World"}
Toster - Understanding the Rails Web Model and Scalability Options
Web App Server and App Framework


         Fully asynchronous using Eventmachine


Lightweight and High Performance (+ 3k req/s in 1 process)


       Rack aware (but not 100% Rack compatible)


    Fibers with EM-Synchrony for easier development
Recap so far ...
Toster - Understanding the Rails Web Model and Scalability Options
Ruby can using Reactors to massively scale


        Good contender to Node.js-style
               (getting better)

One single Ruby process can handle thousands of
              concurrent requests


  Web browsers got smarter with Websockets


     Ruby implements Websocket support
Pusher
Browser           Persistent
                                 connection!


                 async

  Rails App                       Eventmachine App




Resque Queues             sync
Browser           Persistent
                                 connection!


                 async

  Rails App                       Eventmachine App




Resque Queues             sync
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/
jquery.min.js"></script>
<script src="http://js.pusher.com/1.11/pusher.min.js"></script>
<script>
  var pusher = new Pusher('7114e...c318e');
  var channel = pusher.subscribe('demo-channel');




</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/
jquery.min.js"></script>
<script src="http://js.pusher.com/1.11/pusher.min.js"></script>
<script>
  var pusher = new Pusher('7114e...c318e');
  var channel = pusher.subscribe('demo-channel');

  channel.bind('create', function(message) {
    var elem = $("#" + message.elem_id);
    if (elem) elem.remove();
    var html = "<li id='" + message.elem_id + "'>" +
      message.elem_id + " - " + message.value + "</li>";
    $("#list").append(html);
  });

  channel.bind('delete', function(message) {
    var elem = $("#" + message.elem_id);
    if (elem) elem.remove();
  });
</script>
require 'rubygems'
require 'pusher'

Pusher.app_id = '14909'
Pusher.key = '7114e...c318e'
Pusher.secret = '25aa7...3d49c'

('a'..'z').each do |letter|
  doc = { :elem_id => letter,
          :value   => "Letter: #{letter}"}
  Pusher['demo-channel'].trigger('create', doc)
end
time ruby pusher_sync.rb

real 0m14.585s
user 0m0.583s
sys 0m0.105s
require 'rubygems'
require 'pusher'
require 'eventmachine'

Pusher.app_id = '14909'
Pusher.key = '7114e...c318e'
Pusher.secret = '25aa7...d49c'

EM.run do
  EM::Iterator.new("a".."z").each do |letter, iter|
    doc = { :elem_id => elem_id,
            :value   => "Letter: #{letter}" }
    pusher = Pusher['demo-channel'].trigger_async('create', doc)
    pusher.callback { EM.stop if letter == 'z' }
    pusher.errback { |error| EM.stop if letter == 'z' }
    iter.next
  end
end
require 'rubygems'
require 'pusher'
require 'eventmachine'

Pusher.app_id = '14909'
Pusher.key = '7114e...c318e'
Pusher.secret = '25aa7...d49c'

EM.run do
  EM::Iterator.new("a".."z").each do |letter, iter|
    doc = { :elem_id => elem_id,
            :value   => "Letter: #{letter}" }
    pusher = Pusher['demo-channel'].trigger_async('create', doc)
    pusher.callback { EM.stop if letter == 'z' }
    pusher.errback { |error| EM.stop if letter == 'z' }
    iter.next
  end
end
require 'rubygems'
require 'pusher'
require 'eventmachine'

Pusher.app_id = '14909'
Pusher.key = '7114e...c318e'
Pusher.secret = '25aa7...d49c'

EM.run do
  EM::Iterator.new("a".."z").each do |letter, iter|
    doc = { :elem_id => elem_id,
            :value   => "Letter: #{letter}" }
    pusher = Pusher['demo-channel'].trigger_async('create', doc)
    pusher.callback { EM.stop if letter == 'z' }
    pusher.errback { |error| EM.stop if letter == 'z' }
    iter.next
  end
end
time ruby pusher_async.rb

real 0m1.129s
user 0m0.649s
sys 0m0.063s
pusher.connection.bind('connected', function() {
  alert("You're up!")
});

pusher.connection.bind('connecting_in', function(delay) {
  alert("Retrying in " + delay + " seconds.")
});

pusher.connection.bind('failed', function() {
  document.write("Not able to connect.")
});
Toster - Understanding the Rails Web Model and Scalability Options
Private Channels



  Encryption



 Authentication



Presence Events
Toster - Understanding the Rails Web Model and Scalability Options
Total API requests (11/02/2011)

  (day has 86.400 seconds)
13.969.264
 Total API requests (11/02/2011)

   (day has 86.400 seconds)
Amount of messages sent
to clients since launch (11/02/2011)
35.552.810.379
        Amount of messages sent
   to clients since launch (11/02/2011)
average latency (excluding internet - 11/02/2011)
< 10ms
average latency (excluding internet - 11/02/2011)
Wrapping up ...
Toster - Understanding the Rails Web Model and Scalability Options
CGI model is difficult to scale


Multi-processes vs multi-threads vs Reactors


         HTTP 5 WebSockets is hot!


           Eventmachine is great!


       Fibers vs “callback spaghetti”


              Try out Pusher!
CGI model is difficult to scale


Multi-processes vs multi-threads vs Reactors


         HTTP 5 WebSockets is hot!


           Eventmachine is great!


       Fibers vs “callback spaghetti”


              Try out Pusher!
CGI model is difficult to scale


Multi-processes vs multi-threads vs Reactors


         HTTP 5 WebSockets is hot!


           Eventmachine is great!


       Fibers vs “callback spaghetti”


              Try out Pusher!
CGI model is difficult to scale


Multi-processes vs multi-threads vs Reactors


         HTTP 5 WebSockets is hot!


           Eventmachine is great!


       Fibers vs “callback spaghetti”


              Try out Pusher!
CGI model is difficult to scale


Multi-processes vs multi-threads vs Reactors


         HTTP 5 WebSockets is hot!


           Eventmachine is great!


       Fibers vs “callback spaghetti”


              Try out Pusher!
CGI model is difficult to scale


Multi-processes vs multi-threads vs Reactors


         HTTP 5 WebSockets is hot!


           Eventmachine is great!


       Fibers vs “callback spaghetti”


              Try out Pusher!
Ilya Grigorik
   (igvita)
Toster - Understanding the Rails Web Model and Scalability Options
PostRank (acquired by Google!)




    EM-Synchrony, Goliath




    Google SPDY research
Tony Arcieri
 (bascule)
Toster - Understanding the Rails Web Model and Scalability Options
Rev (later Cool.io), Revactor




                   Reia
(Ruby syntax over Erlang, replaced by Elixir)



 Celluloid (Threads abstraction to Actors)
  (Mark Perham used to create Sidekiq)
Ruby is very flexible
one more thing ...
Browser   Browser   Browser   Browser    Browser   Browser




                     NginX, HAProxy


                    Passenger, Unicorn
Browser   Browser   Browser   Browser    Browser   Browser




                     NginX, HAProxy




              JRuby - TorqueBox, Trinidad
           (multiple concurrent native threads)
Toster - Understanding the Rails Web Model and Scalability Options
Native threads
Ruby 1.9.x
             (extensions can release the GIL)



                     Native threads
 JRuby
                        (no GIL)


                     Native threads
Rubinius                 (no GIL
             check out the Puma webserver)
Native threads
Ruby 1.9.x
             (extensions can release the GIL)



                     Native threads
 JRuby
                        (no GIL)


                     Native threads
Rubinius                 (no GIL
             check out the Puma webserver)
Native threads
Ruby 1.9.x
             (extensions can release the GIL)



                     Native threads
 JRuby
                        (no GIL)


                     Native threads
Rubinius                 (no GIL
             check out the Puma webserver)
Toster - Understanding the Rails Web Model and Scalability Options
Toster - Understanding the Rails Web Model and Scalability Options
Toster - Understanding the Rails Web Model and Scalability Options
Большое
спасибо
  www.codeminer.com.br
  www.akitaonrails.com
  @akitaonrails

More Related Content

What's hot

0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-ServicesIlya Grigorik
 
Faster & Greater Messaging System HornetQ zzz
Faster & Greater Messaging System HornetQ zzzFaster & Greater Messaging System HornetQ zzz
Faster & Greater Messaging System HornetQ zzzJBug Italy
 
JUDCon 2010 Boston : BoxGrinder
JUDCon 2010 Boston : BoxGrinderJUDCon 2010 Boston : BoxGrinder
JUDCon 2010 Boston : BoxGrindermarekgoldmann
 
Apache httpd reverse proxy and Tomcat
Apache httpd reverse proxy and TomcatApache httpd reverse proxy and Tomcat
Apache httpd reverse proxy and TomcatJean-Frederic Clere
 
Fisl - Deployment
Fisl - DeploymentFisl - Deployment
Fisl - DeploymentFabio Akita
 
Построение распределенной системы сбора данных с помощью RabbitMQ, Alvaro Vid...
Построение распределенной системы сбора данных с помощью RabbitMQ, Alvaro Vid...Построение распределенной системы сбора данных с помощью RabbitMQ, Alvaro Vid...
Построение распределенной системы сбора данных с помощью RabbitMQ, Alvaro Vid...Ontico
 
Apache httpd 2.4: The Cloud Killer App
Apache httpd 2.4: The Cloud Killer AppApache httpd 2.4: The Cloud Killer App
Apache httpd 2.4: The Cloud Killer AppJim Jagielski
 
Supercharging reflective libraries with InvokeDynamic
Supercharging reflective libraries with InvokeDynamicSupercharging reflective libraries with InvokeDynamic
Supercharging reflective libraries with InvokeDynamicIan Robertson
 
Writing Portable WebSockets in Java
Writing Portable WebSockets in JavaWriting Portable WebSockets in Java
Writing Portable WebSockets in Javajfarcand
 
TorqueBox at DC:JBUG - November 2011
TorqueBox at DC:JBUG - November 2011TorqueBox at DC:JBUG - November 2011
TorqueBox at DC:JBUG - November 2011bobmcwhirter
 
Java/Spring과 Node.js의공존
Java/Spring과 Node.js의공존Java/Spring과 Node.js의공존
Java/Spring과 Node.js의공존동수 장
 
JUDCon 2010 Boston : TorqueBox
JUDCon 2010 Boston : TorqueBoxJUDCon 2010 Boston : TorqueBox
JUDCon 2010 Boston : TorqueBoxmarekgoldmann
 
When Ruby Meets Java - The Power of Torquebox
When Ruby Meets Java - The Power of TorqueboxWhen Ruby Meets Java - The Power of Torquebox
When Ruby Meets Java - The Power of Torqueboxrockyjaiswal
 
"Swoole: double troubles in c", Alexandr Vronskiy
"Swoole: double troubles in c", Alexandr Vronskiy"Swoole: double troubles in c", Alexandr Vronskiy
"Swoole: double troubles in c", Alexandr VronskiyFwdays
 
How to test code with mruby
How to test code with mrubyHow to test code with mruby
How to test code with mrubyHiroshi SHIBATA
 
The Future of library dependency management of Ruby
 The Future of library dependency management of Ruby The Future of library dependency management of Ruby
The Future of library dependency management of RubyHiroshi SHIBATA
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Java/Spring과 Node.js의 공존 시즌2
Java/Spring과 Node.js의 공존 시즌2Java/Spring과 Node.js의 공존 시즌2
Java/Spring과 Node.js의 공존 시즌2동수 장
 
OWASP ZAP Workshop for QA Testers
OWASP ZAP Workshop for QA TestersOWASP ZAP Workshop for QA Testers
OWASP ZAP Workshop for QA TestersJavan Rasokat
 

What's hot (20)

0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
 
Plack at OSCON 2010
Plack at OSCON 2010Plack at OSCON 2010
Plack at OSCON 2010
 
Faster & Greater Messaging System HornetQ zzz
Faster & Greater Messaging System HornetQ zzzFaster & Greater Messaging System HornetQ zzz
Faster & Greater Messaging System HornetQ zzz
 
JUDCon 2010 Boston : BoxGrinder
JUDCon 2010 Boston : BoxGrinderJUDCon 2010 Boston : BoxGrinder
JUDCon 2010 Boston : BoxGrinder
 
Apache httpd reverse proxy and Tomcat
Apache httpd reverse proxy and TomcatApache httpd reverse proxy and Tomcat
Apache httpd reverse proxy and Tomcat
 
Fisl - Deployment
Fisl - DeploymentFisl - Deployment
Fisl - Deployment
 
Построение распределенной системы сбора данных с помощью RabbitMQ, Alvaro Vid...
Построение распределенной системы сбора данных с помощью RabbitMQ, Alvaro Vid...Построение распределенной системы сбора данных с помощью RabbitMQ, Alvaro Vid...
Построение распределенной системы сбора данных с помощью RabbitMQ, Alvaro Vid...
 
Apache httpd 2.4: The Cloud Killer App
Apache httpd 2.4: The Cloud Killer AppApache httpd 2.4: The Cloud Killer App
Apache httpd 2.4: The Cloud Killer App
 
Supercharging reflective libraries with InvokeDynamic
Supercharging reflective libraries with InvokeDynamicSupercharging reflective libraries with InvokeDynamic
Supercharging reflective libraries with InvokeDynamic
 
Writing Portable WebSockets in Java
Writing Portable WebSockets in JavaWriting Portable WebSockets in Java
Writing Portable WebSockets in Java
 
TorqueBox at DC:JBUG - November 2011
TorqueBox at DC:JBUG - November 2011TorqueBox at DC:JBUG - November 2011
TorqueBox at DC:JBUG - November 2011
 
Java/Spring과 Node.js의공존
Java/Spring과 Node.js의공존Java/Spring과 Node.js의공존
Java/Spring과 Node.js의공존
 
JUDCon 2010 Boston : TorqueBox
JUDCon 2010 Boston : TorqueBoxJUDCon 2010 Boston : TorqueBox
JUDCon 2010 Boston : TorqueBox
 
When Ruby Meets Java - The Power of Torquebox
When Ruby Meets Java - The Power of TorqueboxWhen Ruby Meets Java - The Power of Torquebox
When Ruby Meets Java - The Power of Torquebox
 
"Swoole: double troubles in c", Alexandr Vronskiy
"Swoole: double troubles in c", Alexandr Vronskiy"Swoole: double troubles in c", Alexandr Vronskiy
"Swoole: double troubles in c", Alexandr Vronskiy
 
How to test code with mruby
How to test code with mrubyHow to test code with mruby
How to test code with mruby
 
The Future of library dependency management of Ruby
 The Future of library dependency management of Ruby The Future of library dependency management of Ruby
The Future of library dependency management of Ruby
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Java/Spring과 Node.js의 공존 시즌2
Java/Spring과 Node.js의 공존 시즌2Java/Spring과 Node.js의 공존 시즌2
Java/Spring과 Node.js의 공존 시즌2
 
OWASP ZAP Workshop for QA Testers
OWASP ZAP Workshop for QA TestersOWASP ZAP Workshop for QA Testers
OWASP ZAP Workshop for QA Testers
 

Similar to Toster - Understanding the Rails Web Model and Scalability Options

Nodejs a-practical-introduction-oredev
Nodejs a-practical-introduction-oredevNodejs a-practical-introduction-oredev
Nodejs a-practical-introduction-oredevFelix Geisendörfer
 
Dynamic Languages Web Frameworks Indicthreads 2009
Dynamic Languages Web Frameworks Indicthreads 2009Dynamic Languages Web Frameworks Indicthreads 2009
Dynamic Languages Web Frameworks Indicthreads 2009Arun Gupta
 
VUG5: Varnish at Opera Software
VUG5: Varnish at Opera SoftwareVUG5: Varnish at Opera Software
VUG5: Varnish at Opera SoftwareCosimo Streppone
 
Nodejs Explained with Examples
Nodejs Explained with ExamplesNodejs Explained with Examples
Nodejs Explained with ExamplesGabriele Lana
 
Nodejsexplained 101116115055-phpapp02
Nodejsexplained 101116115055-phpapp02Nodejsexplained 101116115055-phpapp02
Nodejsexplained 101116115055-phpapp02Sunny Gupta
 
Isomorphic JavaScript with Nashorn
Isomorphic JavaScript with NashornIsomorphic JavaScript with Nashorn
Isomorphic JavaScript with NashornMaxime Najim
 
Socket applications
Socket applicationsSocket applications
Socket applicationsJoão Moura
 
Cape Cod Web Technology Meetup - 2
Cape Cod Web Technology Meetup - 2Cape Cod Web Technology Meetup - 2
Cape Cod Web Technology Meetup - 2Asher Martin
 
Vert.x – The problem of real-time data binding
Vert.x – The problem of real-time data bindingVert.x – The problem of real-time data binding
Vert.x – The problem of real-time data bindingAlex Derkach
 
Writing highly scalable WebSocket using the Atmosphere Framework and Scala
Writing highly scalable WebSocket using the Atmosphere Framework and ScalaWriting highly scalable WebSocket using the Atmosphere Framework and Scala
Writing highly scalable WebSocket using the Atmosphere Framework and Scalajfarcand
 
Nodejs and WebSockets
Nodejs and WebSocketsNodejs and WebSockets
Nodejs and WebSocketsGonzalo Ayuso
 
Going Live! with Comet
Going Live! with CometGoing Live! with Comet
Going Live! with CometSimon Willison
 
.NET Architects Day - DNAD 2011
.NET Architects Day - DNAD 2011.NET Architects Day - DNAD 2011
.NET Architects Day - DNAD 2011Fabio Akita
 
09 - Fábio Akita - Além do rails
09 - Fábio Akita - Além do rails09 - Fábio Akita - Além do rails
09 - Fábio Akita - Além do railsDNAD
 
Eduardo Silva - monkey http-server everywhere
Eduardo Silva - monkey http-server everywhereEduardo Silva - monkey http-server everywhere
Eduardo Silva - monkey http-server everywhereStarTech Conference
 
WebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
WebSockets: The Current State of the Most Valuable HTML5 API for Java DevelopersWebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
WebSockets: The Current State of the Most Valuable HTML5 API for Java DevelopersViktor Gamov
 

Similar to Toster - Understanding the Rails Web Model and Scalability Options (20)

Deployment de Rails
Deployment de RailsDeployment de Rails
Deployment de Rails
 
The HTML5 WebSocket API
The HTML5 WebSocket APIThe HTML5 WebSocket API
The HTML5 WebSocket API
 
Nodejs a-practical-introduction-oredev
Nodejs a-practical-introduction-oredevNodejs a-practical-introduction-oredev
Nodejs a-practical-introduction-oredev
 
Dynamic Languages Web Frameworks Indicthreads 2009
Dynamic Languages Web Frameworks Indicthreads 2009Dynamic Languages Web Frameworks Indicthreads 2009
Dynamic Languages Web Frameworks Indicthreads 2009
 
VUG5: Varnish at Opera Software
VUG5: Varnish at Opera SoftwareVUG5: Varnish at Opera Software
VUG5: Varnish at Opera Software
 
Nodejs Explained with Examples
Nodejs Explained with ExamplesNodejs Explained with Examples
Nodejs Explained with Examples
 
Nodejsexplained 101116115055-phpapp02
Nodejsexplained 101116115055-phpapp02Nodejsexplained 101116115055-phpapp02
Nodejsexplained 101116115055-phpapp02
 
Isomorphic JavaScript with Nashorn
Isomorphic JavaScript with NashornIsomorphic JavaScript with Nashorn
Isomorphic JavaScript with Nashorn
 
Socket applications
Socket applicationsSocket applications
Socket applications
 
Cape Cod Web Technology Meetup - 2
Cape Cod Web Technology Meetup - 2Cape Cod Web Technology Meetup - 2
Cape Cod Web Technology Meetup - 2
 
Vert.x – The problem of real-time data binding
Vert.x – The problem of real-time data bindingVert.x – The problem of real-time data binding
Vert.x – The problem of real-time data binding
 
Writing highly scalable WebSocket using the Atmosphere Framework and Scala
Writing highly scalable WebSocket using the Atmosphere Framework and ScalaWriting highly scalable WebSocket using the Atmosphere Framework and Scala
Writing highly scalable WebSocket using the Atmosphere Framework and Scala
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
Time for Comet?
Time for Comet?Time for Comet?
Time for Comet?
 
Nodejs and WebSockets
Nodejs and WebSocketsNodejs and WebSockets
Nodejs and WebSockets
 
Going Live! with Comet
Going Live! with CometGoing Live! with Comet
Going Live! with Comet
 
.NET Architects Day - DNAD 2011
.NET Architects Day - DNAD 2011.NET Architects Day - DNAD 2011
.NET Architects Day - DNAD 2011
 
09 - Fábio Akita - Além do rails
09 - Fábio Akita - Além do rails09 - Fábio Akita - Além do rails
09 - Fábio Akita - Além do rails
 
Eduardo Silva - monkey http-server everywhere
Eduardo Silva - monkey http-server everywhereEduardo Silva - monkey http-server everywhere
Eduardo Silva - monkey http-server everywhere
 
WebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
WebSockets: The Current State of the Most Valuable HTML5 API for Java DevelopersWebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
WebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
 

More from Fabio Akita

Devconf 2019 - São Carlos
Devconf 2019 - São CarlosDevconf 2019 - São Carlos
Devconf 2019 - São CarlosFabio Akita
 
Meetup Nerdzão - English Talk about Languages
Meetup Nerdzão  - English Talk about LanguagesMeetup Nerdzão  - English Talk about Languages
Meetup Nerdzão - English Talk about LanguagesFabio Akita
 
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018Fabio Akita
 
Desmistificando Blockchains - 20o Encontro Locaweb SP
Desmistificando Blockchains - 20o Encontro Locaweb SPDesmistificando Blockchains - 20o Encontro Locaweb SP
Desmistificando Blockchains - 20o Encontro Locaweb SPFabio Akita
 
Desmistificando Blockchains - Insiter Goiania
Desmistificando Blockchains - Insiter GoianiaDesmistificando Blockchains - Insiter Goiania
Desmistificando Blockchains - Insiter GoianiaFabio Akita
 
Blockchain em 7 minutos - 7Masters
Blockchain em 7 minutos - 7MastersBlockchain em 7 minutos - 7Masters
Blockchain em 7 minutos - 7MastersFabio Akita
 
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
Elixir  -Tolerância a Falhas para Adultos - GDG CampinasElixir  -Tolerância a Falhas para Adultos - GDG Campinas
Elixir -Tolerância a Falhas para Adultos - GDG CampinasFabio Akita
 
Desmistificando Mitos de Tech Startups - Intercon 2017
Desmistificando Mitos de Tech Startups - Intercon 2017Desmistificando Mitos de Tech Startups - Intercon 2017
Desmistificando Mitos de Tech Startups - Intercon 2017Fabio Akita
 
30 Days to Elixir and Crystal and Back to Ruby
30 Days to Elixir and Crystal and Back to Ruby30 Days to Elixir and Crystal and Back to Ruby
30 Days to Elixir and Crystal and Back to RubyFabio Akita
 
Uma Discussão sobre a Carreira de TI
Uma Discussão sobre a Carreira de TIUma Discussão sobre a Carreira de TI
Uma Discussão sobre a Carreira de TIFabio Akita
 
THE CONF - Opening Keynote
THE CONF - Opening KeynoteTHE CONF - Opening Keynote
THE CONF - Opening KeynoteFabio Akita
 
A Journey through New Languages - Rancho Dev 2017
A Journey through New Languages - Rancho Dev 2017A Journey through New Languages - Rancho Dev 2017
A Journey through New Languages - Rancho Dev 2017Fabio Akita
 
Desmistificando Mitos de Startups - Sebrae - AP
Desmistificando Mitos de Startups - Sebrae - APDesmistificando Mitos de Startups - Sebrae - AP
Desmistificando Mitos de Startups - Sebrae - APFabio Akita
 
A Journey through New Languages - Guru Sorocaba 2017
A Journey through New Languages - Guru Sorocaba 2017A Journey through New Languages - Guru Sorocaba 2017
A Journey through New Languages - Guru Sorocaba 2017Fabio Akita
 
A Journey through New Languages - Insiter 2017
A Journey through New Languages - Insiter 2017A Journey through New Languages - Insiter 2017
A Journey through New Languages - Insiter 2017Fabio Akita
 
A Journey through New Languages - Locaweb Tech Day
A Journey through New Languages - Locaweb Tech DayA Journey through New Languages - Locaweb Tech Day
A Journey through New Languages - Locaweb Tech DayFabio Akita
 
A Journey through new Languages - Intercon 2016
A Journey through new Languages - Intercon 2016A Journey through new Languages - Intercon 2016
A Journey through new Languages - Intercon 2016Fabio Akita
 
Premature Optimization 2.0 - Intercon 2016
Premature Optimization 2.0 - Intercon 2016Premature Optimization 2.0 - Intercon 2016
Premature Optimization 2.0 - Intercon 2016Fabio Akita
 
Conexão Kinghost - Otimização Prematura
Conexão Kinghost - Otimização PrematuraConexão Kinghost - Otimização Prematura
Conexão Kinghost - Otimização PrematuraFabio Akita
 
The Open Commerce Conference - Premature Optimisation: The Root of All Evil
The Open Commerce Conference - Premature Optimisation: The Root of All EvilThe Open Commerce Conference - Premature Optimisation: The Root of All Evil
The Open Commerce Conference - Premature Optimisation: The Root of All EvilFabio Akita
 

More from Fabio Akita (20)

Devconf 2019 - São Carlos
Devconf 2019 - São CarlosDevconf 2019 - São Carlos
Devconf 2019 - São Carlos
 
Meetup Nerdzão - English Talk about Languages
Meetup Nerdzão  - English Talk about LanguagesMeetup Nerdzão  - English Talk about Languages
Meetup Nerdzão - English Talk about Languages
 
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018
 
Desmistificando Blockchains - 20o Encontro Locaweb SP
Desmistificando Blockchains - 20o Encontro Locaweb SPDesmistificando Blockchains - 20o Encontro Locaweb SP
Desmistificando Blockchains - 20o Encontro Locaweb SP
 
Desmistificando Blockchains - Insiter Goiania
Desmistificando Blockchains - Insiter GoianiaDesmistificando Blockchains - Insiter Goiania
Desmistificando Blockchains - Insiter Goiania
 
Blockchain em 7 minutos - 7Masters
Blockchain em 7 minutos - 7MastersBlockchain em 7 minutos - 7Masters
Blockchain em 7 minutos - 7Masters
 
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
Elixir  -Tolerância a Falhas para Adultos - GDG CampinasElixir  -Tolerância a Falhas para Adultos - GDG Campinas
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
 
Desmistificando Mitos de Tech Startups - Intercon 2017
Desmistificando Mitos de Tech Startups - Intercon 2017Desmistificando Mitos de Tech Startups - Intercon 2017
Desmistificando Mitos de Tech Startups - Intercon 2017
 
30 Days to Elixir and Crystal and Back to Ruby
30 Days to Elixir and Crystal and Back to Ruby30 Days to Elixir and Crystal and Back to Ruby
30 Days to Elixir and Crystal and Back to Ruby
 
Uma Discussão sobre a Carreira de TI
Uma Discussão sobre a Carreira de TIUma Discussão sobre a Carreira de TI
Uma Discussão sobre a Carreira de TI
 
THE CONF - Opening Keynote
THE CONF - Opening KeynoteTHE CONF - Opening Keynote
THE CONF - Opening Keynote
 
A Journey through New Languages - Rancho Dev 2017
A Journey through New Languages - Rancho Dev 2017A Journey through New Languages - Rancho Dev 2017
A Journey through New Languages - Rancho Dev 2017
 
Desmistificando Mitos de Startups - Sebrae - AP
Desmistificando Mitos de Startups - Sebrae - APDesmistificando Mitos de Startups - Sebrae - AP
Desmistificando Mitos de Startups - Sebrae - AP
 
A Journey through New Languages - Guru Sorocaba 2017
A Journey through New Languages - Guru Sorocaba 2017A Journey through New Languages - Guru Sorocaba 2017
A Journey through New Languages - Guru Sorocaba 2017
 
A Journey through New Languages - Insiter 2017
A Journey through New Languages - Insiter 2017A Journey through New Languages - Insiter 2017
A Journey through New Languages - Insiter 2017
 
A Journey through New Languages - Locaweb Tech Day
A Journey through New Languages - Locaweb Tech DayA Journey through New Languages - Locaweb Tech Day
A Journey through New Languages - Locaweb Tech Day
 
A Journey through new Languages - Intercon 2016
A Journey through new Languages - Intercon 2016A Journey through new Languages - Intercon 2016
A Journey through new Languages - Intercon 2016
 
Premature Optimization 2.0 - Intercon 2016
Premature Optimization 2.0 - Intercon 2016Premature Optimization 2.0 - Intercon 2016
Premature Optimization 2.0 - Intercon 2016
 
Conexão Kinghost - Otimização Prematura
Conexão Kinghost - Otimização PrematuraConexão Kinghost - Otimização Prematura
Conexão Kinghost - Otimização Prematura
 
The Open Commerce Conference - Premature Optimisation: The Root of All Evil
The Open Commerce Conference - Premature Optimisation: The Root of All EvilThe Open Commerce Conference - Premature Optimisation: The Root of All Evil
The Open Commerce Conference - Premature Optimisation: The Root of All Evil
 

Recently uploaded

TrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie WorldTrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie WorldTrustArc
 
Planetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile BrochurePlanetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile BrochurePlanetek Italia Srl
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfCheryl Hung
 
The New Cloud World Order Is FinOps (Slideshow)
The New Cloud World Order Is FinOps (Slideshow)The New Cloud World Order Is FinOps (Slideshow)
The New Cloud World Order Is FinOps (Slideshow)codyslingerland1
 
LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0DanBrown980551
 
Explore the UiPath Community and ways you can benefit on your journey to auto...
Explore the UiPath Community and ways you can benefit on your journey to auto...Explore the UiPath Community and ways you can benefit on your journey to auto...
Explore the UiPath Community and ways you can benefit on your journey to auto...DianaGray10
 
The Zero-ETL Approach: Enhancing Data Agility and Insight
The Zero-ETL Approach: Enhancing Data Agility and InsightThe Zero-ETL Approach: Enhancing Data Agility and Insight
The Zero-ETL Approach: Enhancing Data Agility and InsightSafe Software
 
AI Workshops at Computers In Libraries 2024
AI Workshops at Computers In Libraries 2024AI Workshops at Computers In Libraries 2024
AI Workshops at Computers In Libraries 2024Brian Pichman
 
3 Pitfalls Everyone Should Avoid with Cloud Data
3 Pitfalls Everyone Should Avoid with Cloud Data3 Pitfalls Everyone Should Avoid with Cloud Data
3 Pitfalls Everyone Should Avoid with Cloud DataEric D. Schabell
 
Automation Ops Series: Session 2 - Governance for UiPath projects
Automation Ops Series: Session 2 - Governance for UiPath projectsAutomation Ops Series: Session 2 - Governance for UiPath projects
Automation Ops Series: Session 2 - Governance for UiPath projectsDianaGray10
 
UiPath Studio Web workshop series - Day 1
UiPath Studio Web workshop series  - Day 1UiPath Studio Web workshop series  - Day 1
UiPath Studio Web workshop series - Day 1DianaGray10
 
CyberSecurity - Computers In Libraries 2024
CyberSecurity - Computers In Libraries 2024CyberSecurity - Computers In Libraries 2024
CyberSecurity - Computers In Libraries 2024Brian Pichman
 
UiPath Studio Web workshop Series - Day 3
UiPath Studio Web workshop Series - Day 3UiPath Studio Web workshop Series - Day 3
UiPath Studio Web workshop Series - Day 3DianaGray10
 
Scenario Library et REX Discover industry- and role- based scenarios
Scenario Library et REX Discover industry- and role- based scenariosScenario Library et REX Discover industry- and role- based scenarios
Scenario Library et REX Discover industry- and role- based scenariosErol GIRAUDY
 
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdf
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdfQ4 2023 Quarterly Investor Presentation - FINAL - v1.pdf
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdfTejal81
 
20140402 - Smart house demo kit
20140402 - Smart house demo kit20140402 - Smart house demo kit
20140402 - Smart house demo kitJamie (Taka) Wang
 
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptxEmil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptxNeo4j
 
Webinar: The Art of Prioritizing Your Product Roadmap by AWS Sr PM - Tech
Webinar: The Art of Prioritizing Your Product Roadmap by AWS Sr PM - TechWebinar: The Art of Prioritizing Your Product Roadmap by AWS Sr PM - Tech
Webinar: The Art of Prioritizing Your Product Roadmap by AWS Sr PM - TechProduct School
 
2024.03.12 Cost drivers of cultivated meat production.pdf
2024.03.12 Cost drivers of cultivated meat production.pdf2024.03.12 Cost drivers of cultivated meat production.pdf
2024.03.12 Cost drivers of cultivated meat production.pdfThe Good Food Institute
 

Recently uploaded (20)

TrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie WorldTrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie World
 
Planetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile BrochurePlanetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile Brochure
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
The New Cloud World Order Is FinOps (Slideshow)
The New Cloud World Order Is FinOps (Slideshow)The New Cloud World Order Is FinOps (Slideshow)
The New Cloud World Order Is FinOps (Slideshow)
 
LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0
 
SheDev 2024
SheDev 2024SheDev 2024
SheDev 2024
 
Explore the UiPath Community and ways you can benefit on your journey to auto...
Explore the UiPath Community and ways you can benefit on your journey to auto...Explore the UiPath Community and ways you can benefit on your journey to auto...
Explore the UiPath Community and ways you can benefit on your journey to auto...
 
The Zero-ETL Approach: Enhancing Data Agility and Insight
The Zero-ETL Approach: Enhancing Data Agility and InsightThe Zero-ETL Approach: Enhancing Data Agility and Insight
The Zero-ETL Approach: Enhancing Data Agility and Insight
 
AI Workshops at Computers In Libraries 2024
AI Workshops at Computers In Libraries 2024AI Workshops at Computers In Libraries 2024
AI Workshops at Computers In Libraries 2024
 
3 Pitfalls Everyone Should Avoid with Cloud Data
3 Pitfalls Everyone Should Avoid with Cloud Data3 Pitfalls Everyone Should Avoid with Cloud Data
3 Pitfalls Everyone Should Avoid with Cloud Data
 
Automation Ops Series: Session 2 - Governance for UiPath projects
Automation Ops Series: Session 2 - Governance for UiPath projectsAutomation Ops Series: Session 2 - Governance for UiPath projects
Automation Ops Series: Session 2 - Governance for UiPath projects
 
UiPath Studio Web workshop series - Day 1
UiPath Studio Web workshop series  - Day 1UiPath Studio Web workshop series  - Day 1
UiPath Studio Web workshop series - Day 1
 
CyberSecurity - Computers In Libraries 2024
CyberSecurity - Computers In Libraries 2024CyberSecurity - Computers In Libraries 2024
CyberSecurity - Computers In Libraries 2024
 
UiPath Studio Web workshop Series - Day 3
UiPath Studio Web workshop Series - Day 3UiPath Studio Web workshop Series - Day 3
UiPath Studio Web workshop Series - Day 3
 
Scenario Library et REX Discover industry- and role- based scenarios
Scenario Library et REX Discover industry- and role- based scenariosScenario Library et REX Discover industry- and role- based scenarios
Scenario Library et REX Discover industry- and role- based scenarios
 
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdf
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdfQ4 2023 Quarterly Investor Presentation - FINAL - v1.pdf
Q4 2023 Quarterly Investor Presentation - FINAL - v1.pdf
 
20140402 - Smart house demo kit
20140402 - Smart house demo kit20140402 - Smart house demo kit
20140402 - Smart house demo kit
 
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptxEmil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
 
Webinar: The Art of Prioritizing Your Product Roadmap by AWS Sr PM - Tech
Webinar: The Art of Prioritizing Your Product Roadmap by AWS Sr PM - TechWebinar: The Art of Prioritizing Your Product Roadmap by AWS Sr PM - Tech
Webinar: The Art of Prioritizing Your Product Roadmap by AWS Sr PM - Tech
 
2024.03.12 Cost drivers of cultivated meat production.pdf
2024.03.12 Cost drivers of cultivated meat production.pdf2024.03.12 Cost drivers of cultivated meat production.pdf
2024.03.12 Cost drivers of cultivated meat production.pdf
 

Toster - Understanding the Rails Web Model and Scalability Options

  • 1. “ Genius is the gold in the mine; talent is the miner who works and brings it out. ” Lady Marguerite Blessington Donets Basin Coal Mine-Ukraine
  • 2. “ Genius is the gold in the mine; talent is the miner who works and brings it out. ” Lady Marguerite Blessington Презентация начнется в течение нескольких минут ... Donets Basin Coal Mine-Ukraine
  • 4. Fabio Akita, Co-Founder @CodeMiner42
  • 5. “Off-centered software for off-centered people” Fabio Akita, Co-Founder @CodeMiner42
  • 8. Understanding the Rails Web Model and Scalability Options
  • 9. ?
  • 16. CGI
  • 17. 1 request blocks 1 process
  • 18. require 'rubygems' require 'rack' class Test def call(env) sleep 1 # on purpose, simulating a blocking operation [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] end end Rack::Handler::Thin.run Test.new
  • 19. require 'rubygems' require 'rack' class Test def call(env) sleep 1 # on purpose, simulating a blocking operation [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] end end Rack::Handler::Thin.run Test.new
  • 20. $ rackup config.ru >> Thin web server (v1.3.1 codename Triple Espresso) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:8080, CTRL+C to stop
  • 21. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 1 Time taken for tests: 10.020 seconds ... Requests per second: 1.00 [#/sec] (mean) Time per request: 1002.015 [ms] (mean) Time per request: 1002.015 [ms] (mean, across all concurrent requests) Transfer rate: 0.12 [Kbytes/sec] received ...
  • 22. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 1 Time taken for tests: 10.020 seconds ... Requests per second: 1.00 [#/sec] (mean) Time per request: 1002.015 [ms] (mean) Time per request: 1002.015 [ms] (mean, across all concurrent requests) Transfer rate: 0.12 [Kbytes/sec] received ...
  • 23. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 1 Time taken for tests: 10.020 seconds ... Requests per second: 1.00 [#/sec] (mean) Time per request: 1002.015 [ms] (mean) Time per request: 1002.015 [ms] (mean, across all concurrent requests) Transfer rate: 0.12 [Kbytes/sec] received ...
  • 24. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 1 Time taken for tests: 10.020 seconds ... Requests per second: 1.00 [#/sec] (mean) Time per request: 1002.015 [ms] (mean) Time per request: 1002.015 [ms] (mean, across all concurrent requests) Transfer rate: 0.12 [Kbytes/sec] received ...
  • 25. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 1 Time taken for tests: 10.020 seconds ... Requests per second: 1.00 [#/sec] (mean) Time per request: 1002.015 [ms] (mean) Time per request: 1002.015 [ms] (mean, across all concurrent requests) Transfer rate: 0.12 [Kbytes/sec] received ...
  • 26. Browser Browser Browser Browser Browser Browser NginX, HAProxy Passenger, Unicorn
  • 28. Browser Browser Browser Browser Browser Browser NginX, HAProxy Passenger, Unicorn (CoW GC - REE or MRI 2)
  • 30. Ruby Enterprise Edition 1.8.7 Copy on Write patched (about to be deprecated) mark and sweep GC Ruby 1.9.2 (current) mark and sweep GC Ruby 1.9.3 (transitioning) Lazy Sweep GC Copy on Write compatible Ruby 2.0 (future) Bitmap Marking GC
  • 31. Ruby Enterprise Edition 1.8.7 Copy on Write patched (about to be deprecated) mark and sweep GC Ruby 1.9.2 (current) mark and sweep GC Ruby 1.9.3 (transitioning) Lazy Sweep GC Copy on Write compatible Ruby 2.0 (future) Bitmap Marking GC
  • 32. Ruby Enterprise Edition 1.8.7 Copy on Write patched (about to be deprecated) mark and sweep GC Ruby 1.9.2 (current) mark and sweep GC Ruby 1.9.3 (transitioning) Lazy Sweep GC Copy on Write compatible Ruby 2.0 (future) Bitmap Marking GC
  • 33. Ruby Enterprise Edition 1.8.7 Copy on Write patched (about to be deprecated) mark and sweep GC Ruby 1.9.2 (current) mark and sweep GC Ruby 1.9.3 (transitioning) Lazy Sweep GC Copy on Write compatible Ruby 2.0 (future) Bitmap Marking GC
  • 34. Browser Browser Browser Browser NginX, HAProxy Passenger, Unicorn
  • 35. Browser Browser Browser Browser NginX, HAProxy Passenger, Unicorn Memcached
  • 36. Browser Browser Browser Browser Varnish NginX, HAProxy Passenger, Unicorn Memcached
  • 37. Browser Browser Browser Browser Varnish NginX, HAProxy Passenger, Unicorn Resque Memcached
  • 38. Browser Browser Browser Browser Varnish NginX, HAProxy Passenger, Unicorn Resque Memcached
  • 41. Notifications and Events in general Online Gaming Chatting and Presence Collaborative Applications Advanced and more Interactive UI
  • 42. (function poll(){ $.ajax({ url: "server", success: function(data){ // do something with the received ‘data’ //Setup the next poll recursively poll(); }, dataType: "json"}); })();
  • 43. (function poll(){ setTimeout(function(){ $.ajax({ url: "server", success: function(data){ // do something with the received ‘data’ //Setup the next poll recursively poll(); }, dataType: "json"}); }, 5000); })();
  • 45. Cross Frame communication HTTP Polling (Ajax) Liveconnect (Java applets, Flash socket) Long Polling Comet & HTTP Streaming (ex. forever frame/chunked encode)
  • 48. W3C/IETF Standard - RFC 6455 (12/2011) Full duplex persistent communication channel Less overhead than HTTP (down to 2 bytes per frame) No latency (no reconnections) No polling overhead (on demand) “Upgrades” HTTP, uses 80/443 (kind of friendly to existing proxies)
  • 49. <script type="text/javascript"> var ws = new WebSocket("ws://example.com:10081/"); </script>
  • 50. <script type="text/javascript"> var ws = new WebSocket("ws://example.com:10081/"); ws.onopen = function() { ws.send("Hello"); // Sends a message. }; ws.onmessage = function(e) { // Receives a message. alert(e.data); }; ws.onclose = function() { alert("closed"); }; </script>
  • 52. Protocol IE Firefox Chrome Safari Opera hixie-75 4 5 hixie-76 4 6 5.0.1 11 hybi-00 (disabled) (disabled) hybi-06 HTML5 Labs dev hybi-07 6 hybi-09 HTML5 Labs hybi-10 IE 10 7 14 RFC 6455 11 16
  • 53. POLYFILL/FALLBACK (web-socket-js)
  • 54. <script type="text/javascript" src="swfobject.js"></script> <script type="text/javascript" src="web_socket.js"></script> <script type="text/javascript"> // Let the library know where WebSocketMain.swf is: WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf"; var ws = new WebSocket("ws://example.com:10081/"); ws.onopen = function() { ws.send("Hello"); // Sends a message. }; ws.onmessage = function(e) { // Receives a message. alert(e.data); }; ws.onclose = function() { alert("closed"); }; </script>
  • 55. <script type="text/javascript" src="swfobject.js"></script> <script type="text/javascript" src="web_socket.js"></script> <script type="text/javascript"> // Let the library know where WebSocketMain.swf is: WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf"; var ws = new WebSocket("ws://example.com:10081/"); ws.onopen = function() { ws.send("Hello"); // Sends a message. }; ws.onmessage = function(e) { // Receives a message. alert(e.data); }; ws.onclose = function() { alert("closed"); }; </script>
  • 56. <script type="text/javascript" src="swfobject.js"></script> <script type="text/javascript" src="web_socket.js"></script> <script type="text/javascript"> // Let the library know where WebSocketMain.swf is: WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf"; var ws = new WebSocket("ws://example.com:10081/"); ws.onopen = function() { ws.send("Hello"); // Sends a message. }; ws.onmessage = function(e) { // Receives a message. alert(e.data); }; ws.onclose = function() { alert("closed"); }; </script>
  • 57. <script type="text/javascript" src="swfobject.js"></script> <script type="text/javascript" src="web_socket.js"></script> <script type="text/javascript"> // Let the library know where WebSocketMain.swf is: WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf"; var ws = new WebSocket("ws://example.com:10081/"); ws.onopen = function() { ws.send("Hello"); // Sends a message. }; ws.onmessage = function(e) { // Receives a message. alert(e.data); }; ws.onclose = function() { alert("closed"); }; </script>
  • 58. <script type="text/javascript" src="swfobject.js"></script> <script type="text/javascript" src="web_socket.js"></script> <script type="text/javascript"> // Let the library know where WebSocketMain.swf is: WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf"; var ws = new WebSocket("ws://example.com:10081/"); ws.onopen = function() { ws.send("Hello"); // Sends a message. }; ws.onmessage = function(e) { // Receives a message. alert(e.data); }; ws.onclose = function() { alert("closed"); }; </script>
  • 59. Client: kind of OK Server: what do do?
  • 61. Reactor Pattern (Eventmachine)
  • 63. synchronous I/O non-blocking synchronous I/O non-blocking asynchronous I/0
  • 64. Wait Events (I/O, timers) Main Loop Notifies Event (main thread) Handlers
  • 66. select poll
  • 67. select poll epoll kqueue IOCP
  • 68. libevent libev select poll epoll kqueue IOCP
  • 69. Tornado Twisted libevent libev select poll epoll kqueue IOCP
  • 70. Tornado Twisted Node.js libevent libev select poll epoll kqueue IOCP
  • 71. Tornado Cool.io Twisted Node.js libevent libev select poll epoll kqueue IOCP
  • 72. Tornado Cool.io Twisted Node.js libevent libev EventMachine select poll epoll kqueue IOCP
  • 73. Tornado Cool.io Goliath Twisted Node.js Thin libevent libev EventMachine select poll epoll kqueue IOCP
  • 74. require 'rubygems' require 'rack' class Test def call(env) sleep 1 # on purpose, simulating a blocking operation [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] end end Rack::Handler::Thin.run Test.new
  • 75. require 'rubygems' require 'rack' class Test def call(env) EM.defer do sleep 1 # CPU bound, throw to thread-pool (cheating) end [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] end end Rack::Handler::Thin.run Test.new
  • 76. require 'rubygems' require 'rack' class Test def call(env) EM.defer do sleep 1 # CPU bound, throw to thread-pool (cheating) end [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] end end Rack::Handler::Thin.run Test.new
  • 77. require 'rubygems' require 'rack' class Test def call(env) EM.defer do sleep 1 # CPU bound, throw to thread-pool (cheating) end [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] end end Rack::Handler::Thin.run Test.new
  • 78. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 1 Time taken for tests: 0.003 seconds ... Requests per second: 3219.58 [#/sec] (mean) Time per request: 0.311 [ms] (mean) Time per request: 0.311 [ms] (mean, across all concurrent requests) Transfer rate: 380.44 [Kbytes/sec] received ...
  • 79. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 1 Time taken for tests: 0.003 seconds ... Requests per second: 3219.58 [#/sec] (mean) Time per request: 0.311 [ms] (mean) Time per request: 0.311 [ms] (mean, across all concurrent requests) Transfer rate: 380.44 [Kbytes/sec] received ...
  • 80. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 1 Time taken for tests: 0.003 seconds ... Requests per second: 3219.58 [#/sec] (mean) Time per request: 0.311 [ms] (mean) Time per request: 0.311 [ms] (mean, across all concurrent requests) Transfer rate: 380.44 [Kbytes/sec] received ...
  • 81. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 1 Time taken for tests: 0.003 seconds ... Requests per second: 3219.58 [#/sec] (mean) Time per request: 0.311 [ms] (mean) Time per request: 0.311 [ms] (mean, across all concurrent requests) Transfer rate: 380.44 [Kbytes/sec] received ...
  • 82. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 1 Time taken for tests: 0.003 seconds ... Requests per second: 3219.58 [#/sec] (mean) Time per request: 0.311 [ms] (mean) Time per request: 0.311 [ms] (mean, across all concurrent requests) Transfer rate: 380.44 [Kbytes/sec] received ...
  • 83. ab -n 10 -c 1 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> #ZOMG! ... Concurrency Level: 1 Time taken for tests: 0.003 seconds ... Requests per second: 3219.58 [#/sec] (mean) Time per request: 0.311 [ms] (mean) Time per request: 0.311 [ms] (mean, across all concurrent requests) Transfer rate: 380.44 [Kbytes/sec] received ...
  • 84. ab -n 10 -c 10 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 10 Time taken for tests: 0.002 seconds ... Requests per second: 5211.05 [#/sec] (mean) Time per request: 1.919 [ms] (mean) Time per request: 0.192 [ms] (mean, across all concurrent requests) Transfer rate: 615.76 [Kbytes/sec] received ...
  • 86. Block Non-Block Total Time 10 sec 0.0001 sec Requests per Second 1 + 8000
  • 87. Block Non-Block Total Time 10 sec 0.0001 sec Requests per Second 1 + 8000
  • 88. Block Non-Block Total Time 10 sec 0.0001 sec Requests per Second 1 + 8000
  • 89. “Tick” Timers #add_timer #add_periodic_timer Reactor Loop Blocking Tasks (Eventmachine) #defer #next_tick
  • 90. require 'rubygems' # or use Bundler.setup require 'eventmachine' class EchoServer < EM::Connection def receive_data(data) if data.strip =~ /[exit|quit]$/i EM.stop else send_data("Repeating: #{data}") end end end
  • 91. require 'rubygems' # or use Bundler.setup require 'eventmachine' class EchoServer < EM::Connection def receive_data(data) if data.strip =~ /[exit|quit]$/i EM.stop else send_data("Repeating: #{data}") end end end EventMachine.run do # hit Control + C to stop Signal.trap("INT") { EM.stop } Signal.trap("TERM") { EM.stop } EM.start_server("0.0.0.0", 10000, EchoServer) end
  • 92. $ telnet localhost 10000 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello World
  • 93. $ telnet localhost 10000 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello World Repeating: Hello World
  • 94. $ telnet localhost 10000 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello World Repeating: Hello World Play again, Sam
  • 95. $ telnet localhost 10000 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello World Repeating: Hello World Play again, Sam Repeating: Play again, Sam
  • 96. $ telnet localhost 10000 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello World Repeating: Hello World Play again, Sam Repeating: Play again, Sam quit .
  • 97. $ telnet localhost 10000 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello World Repeating: Hello World Play again, Sam Repeating: Play again, Sam quit Connection closed by foreign host.
  • 98. require 'rubygems' require 'eventmachine' EM.run do # ... main reactor loop EM.stop # stop the main loop and exit end
  • 101. require 'rubygems' require 'eventmachine' EM.run do EM.defer do sleep 3 puts 1 end EM.add_timer(1) do puts 2 EM.add_timer(1) do puts 3 end end puts 4 end
  • 104. var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World'); }).listen(9876);
  • 105. ab -n 1000 -c 5 http://127.0.0.1:9876/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 5 Time taken for tests: 0.124 seconds ... Requests per second: 8035.36 [#/sec] (mean) Time per request: 0.622 [ms] (mean) Time per request: 0.124 [ms] (mean, across all concurrent requests) Transfer rate: 588.53 [Kbytes/sec] received ...
  • 106. require 'rubygems' require 'rack' Rack::Handler::Thin.run Proc.new { [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] }
  • 107. ab -n 1000 -c 5 http://127.0.0.1:8080/ This is ApacheBench, Version 2.3 <$Revision: 1178079 $> ... Concurrency Level: 5 Time taken for tests: 0.121 seconds .. Requests per second: 8239.06 [#/sec] (mean) Time per request: 0.607 [ms] (mean) Time per request: 0.121 [ms] (mean, across all concurrent requests) Transfer rate: 973.56 [Kbytes/sec] received ...
  • 109. Node.js Ruby libev Eventmachine, Cool.io Google V8 MRI, JRuby, Rubinius Less Resources, Faster More Resources, Slightly Processing slower processing callbacks only Threads, Fibers, Callbacks
  • 110. Node.js Ruby libev Eventmachine, Cool.io Google V8 MRI, JRuby, Rubinius Less Resources, Faster More Resources, Slightly Processing slower processing callbacks only Threads, Fibers, Callbacks
  • 111. Node.js Ruby libev Eventmachine, Cool.io Google V8 MRI, JRuby, Rubinius Less Resources, Faster More Resources, Slightly Processing slower processing callbacks only Threads, Fibers, Callbacks
  • 112. Node.js Ruby libev Eventmachine, Cool.io Google V8 MRI, JRuby, Rubinius Less Resources, Faster More Resources, Slightly Processing slower processing callbacks only Threads, Fibers, Callbacks
  • 113. Node.js Ruby libev Eventmachine, Cool.io Google V8 MRI, JRuby, Rubinius Less Resources, Faster More Resources, Slightly Processing slower processing callbacks only Threads, Fibers, Callbacks
  • 115. require "rubygems" require 'eventmachine' require 'em-websocket' config = {:host => "0.0.0.0", :port => 8080, :debug => true} EM::WebSocket.start(config) do |ws| ws.onopen { ws.send "Welcome!"} ws.onmessage { |msg| ws.send "Sending Pong: #{msg}" } ws.onclose { puts "connection closed" } ws.onerror { |e| puts "Error: #{e.message}" } end
  • 116. Caveats in Callback Driven Development
  • 117. fs.rename('/tmp/hello', '/tmp/world', function (err) { if (err) throw err; console.log('renamed complete'); }); fs.stat('/tmp/world', function (err, stats) { if (err) throw err; console.log('stats: ' + JSON.stringify(stats)); });
  • 118. fs.rename('/tmp/hello', '/tmp/world', function (err) { if (err) throw err; fs.stat('/tmp/world', function (err, stats) { if (err) throw err; console.log('stats: ' + JSON.stringify(stats)); }); });
  • 119. EM.run do page = EM::HttpRequest.new(@url1).get page.errback do puts "Site is down! terminate?" end page.callback do about = EM::HttpRequest.new(@url2).get about.callback do # callback nesting, ad infinitum end about.errback do # error-handling code end end end
  • 121. Ruby 1.9 Fibers to the rescue!
  • 122. number_generator = Fiber.new do start = 0 loop do start += 1 Fiber.yield(start) end end
  • 123. number_generator = Fiber.new do start = 0 loop do start += 1 Fiber.yield(start) end end > number_generator.resume => 1
  • 124. number_generator = Fiber.new do start = 0 loop do start += 1 Fiber.yield(start) end end > number_generator.resume => 1 > number_generator.resume => 2
  • 125. number_generator = Fiber.new do start = 0 loop do start += 1 Fiber.yield(start) end end > number_generator.resume => 1 > number_generator.resume => 2 > number_generator.resume => 3
  • 127. Less expensive than Threads cooperative vs preemptive multitasking developer controls scheduling no need to have mutexes, no shared data coroutines / can be implemented with continuations
  • 128. Less expensive than Threads cooperative vs preemptive multitasking developer controls scheduling no need to have mutexes, no shared data coroutines / can be implemented with continuations
  • 129. Less expensive than Threads cooperative vs preemptive multitasking developer controls scheduling no need to have mutexes, no shared data coroutines / can be implemented with continuations
  • 130. Less expensive than Threads cooperative vs preemptive multitasking developer controls scheduling no need to have mutexes, no shared data coroutines / can be implemented with continuations
  • 131. Less expensive than Threads cooperative vs preemptive multitasking developer controls scheduling no need to have mutexes, no shared data coroutines / can be implemented with continuations
  • 132. EM.run do page = EM::HttpRequest.new(@url1).get page.errback do puts "Site is down! terminate?" end page.callback do about = EM::HttpRequest.new(@url2).get about.callback do # callback nesting, ad infinitum end about.errback do # error-handling code end end end
  • 133. page = http_get(@url1) puts "Fetched page: #{page.response_header.status}" if page page = http_get(@url2) puts "Fetched page 2: #{page.response_header.status}" end
  • 134. def http_get(url) f = Fiber.current http = EM::HttpRequest.new(url).get http.callback{ f.resume(http) } http.errback { f.resume(http) } return Fiber.yield end EM.run do Fiber.new do page = http_get(@url1) puts "Fetched page: #{page.response_header.status}" if page page = http_get(@url2) puts "Fetched page 2: #{page.response_header.status}" end do.resume end
  • 135. def http_get(url) f = Fiber.current http = EM::HttpRequest.new(url).get http.callback{ f.resume(http) } http.errback { f.resume(http) } return Fiber.yield end EM.run do Fiber.new do page = http_get(@url1) puts "Fetched page: #{page.response_header.status}" if page page = http_get(@url2) puts "Fetched page 2: #{page.response_header.status}" end do.resume end
  • 136. def http_get(url) f = Fiber.current http = EM::HttpRequest.new(url).get http.callback{ f.resume(http) } http.errback { f.resume(http) } return Fiber.yield end EM.run do Fiber.new do page = http_get(@url1) puts "Fetched page: #{page.response_header.status}" if page page = http_get(@url2) puts "Fetched page 2: #{page.response_header.status}" end do.resume end
  • 137. def http_get(url) f = Fiber.current http = EM::HttpRequest.new(url).get http.callback{ f.resume(http) } http.errback { f.resume(http) } return Fiber.yield end EM.run do Fiber.new do page = http_get(@url1) puts "Fetched page: #{page.response_header.status}" if page page = http_get(@url2) puts "Fetched page 2: #{page.response_header.status}" end do.resume end
  • 138. def http_get(url) f = Fiber.current http = EM::HttpRequest.new(url).get http.callback{ f.resume(http) } http.errback { f.resume(http) } return Fiber.yield end EM.run do Fiber.new do page = http_get(@url1) puts "Fetched page: #{page.response_header.status}" if page page = http_get(@url2) puts "Fetched page 2: #{page.response_header.status}" end do.resume end
  • 139. def http_get(url) f = Fiber.current http = EM::HttpRequest.new(url).get http.callback{ f.resume(http) } http.errback { f.resume(http) } return Fiber.yield end EM.run do Fiber.new do page = http_get(@url1) puts "Fetched page: #{page.response_header.status}" if page page = http_get(@url2) puts "Fetched page 2: #{page.response_header.status}" end do.resume end
  • 140. def http_get(url) f = Fiber.current http = EM::HttpRequest.new(url).get http.callback{ f.resume(http) } http.errback { f.resume(http) } return Fiber.yield end EM.run do Fiber.new do page = http_get(@url1) puts "Fetched page: #{page.response_header.status}" if page page = http_get(@url2) puts "Fetched page 2: #{page.response_header.status}" end do.resume end
  • 142. EM.synchrony do page = EM::HttpRequest.new("http://www.google.com").get puts "Look Ma! No callbacks! Fetched page: #{page}" EM.stop end # old way EM.run do page = EM::HttpRequest.new("http://www.google.com").get page.callback do puts "Lame ... Fetched page: #{page}" EM.stop end end
  • 144. require 'goliath' require 'yajl' G = Goliath::Rack # don’t to this, just to fit in this slide :-) class Echo < Goliath::API use G::Render, 'json' # auto-negotiate response format use G::Params # parse & merge query and body parameters use G::Validation::RequiredParam, {:key => 'echo'} def process_request logger.info "Processing request" {response: env.params['echo']} end def response(env) [200, {}, process_request] end end
  • 145. $ ruby echo.rb -p 9001
  • 146. $ ruby echo.rb -p 9001 $ curl http://localhost:9001/ {"error":"Echo identifier missing"}
  • 147. $ ruby echo.rb -p 9001 $ curl http://localhost:9001/ {"error":"Echo identifier missing"} $ curl http://localhost:9001?echo=Hello%20World {"response":"Hello World"}
  • 149. Web App Server and App Framework Fully asynchronous using Eventmachine Lightweight and High Performance (+ 3k req/s in 1 process) Rack aware (but not 100% Rack compatible) Fibers with EM-Synchrony for easier development
  • 150. Recap so far ...
  • 152. Ruby can using Reactors to massively scale Good contender to Node.js-style (getting better) One single Ruby process can handle thousands of concurrent requests Web browsers got smarter with Websockets Ruby implements Websocket support
  • 153. Pusher
  • 154. Browser Persistent connection! async Rails App Eventmachine App Resque Queues sync
  • 155. Browser Persistent connection! async Rails App Eventmachine App Resque Queues sync
  • 157. <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/ jquery.min.js"></script> <script src="http://js.pusher.com/1.11/pusher.min.js"></script> <script> var pusher = new Pusher('7114e...c318e'); var channel = pusher.subscribe('demo-channel'); channel.bind('create', function(message) { var elem = $("#" + message.elem_id); if (elem) elem.remove(); var html = "<li id='" + message.elem_id + "'>" + message.elem_id + " - " + message.value + "</li>"; $("#list").append(html); }); channel.bind('delete', function(message) { var elem = $("#" + message.elem_id); if (elem) elem.remove(); }); </script>
  • 158. require 'rubygems' require 'pusher' Pusher.app_id = '14909' Pusher.key = '7114e...c318e' Pusher.secret = '25aa7...3d49c' ('a'..'z').each do |letter| doc = { :elem_id => letter, :value => "Letter: #{letter}"} Pusher['demo-channel'].trigger('create', doc) end
  • 159. time ruby pusher_sync.rb real 0m14.585s user 0m0.583s sys 0m0.105s
  • 160. require 'rubygems' require 'pusher' require 'eventmachine' Pusher.app_id = '14909' Pusher.key = '7114e...c318e' Pusher.secret = '25aa7...d49c' EM.run do EM::Iterator.new("a".."z").each do |letter, iter| doc = { :elem_id => elem_id, :value => "Letter: #{letter}" } pusher = Pusher['demo-channel'].trigger_async('create', doc) pusher.callback { EM.stop if letter == 'z' } pusher.errback { |error| EM.stop if letter == 'z' } iter.next end end
  • 161. require 'rubygems' require 'pusher' require 'eventmachine' Pusher.app_id = '14909' Pusher.key = '7114e...c318e' Pusher.secret = '25aa7...d49c' EM.run do EM::Iterator.new("a".."z").each do |letter, iter| doc = { :elem_id => elem_id, :value => "Letter: #{letter}" } pusher = Pusher['demo-channel'].trigger_async('create', doc) pusher.callback { EM.stop if letter == 'z' } pusher.errback { |error| EM.stop if letter == 'z' } iter.next end end
  • 162. require 'rubygems' require 'pusher' require 'eventmachine' Pusher.app_id = '14909' Pusher.key = '7114e...c318e' Pusher.secret = '25aa7...d49c' EM.run do EM::Iterator.new("a".."z").each do |letter, iter| doc = { :elem_id => elem_id, :value => "Letter: #{letter}" } pusher = Pusher['demo-channel'].trigger_async('create', doc) pusher.callback { EM.stop if letter == 'z' } pusher.errback { |error| EM.stop if letter == 'z' } iter.next end end
  • 163. time ruby pusher_async.rb real 0m1.129s user 0m0.649s sys 0m0.063s
  • 164. pusher.connection.bind('connected', function() { alert("You're up!") }); pusher.connection.bind('connecting_in', function(delay) { alert("Retrying in " + delay + " seconds.") }); pusher.connection.bind('failed', function() { document.write("Not able to connect.") });
  • 166. Private Channels Encryption Authentication Presence Events
  • 168. Total API requests (11/02/2011) (day has 86.400 seconds)
  • 169. 13.969.264 Total API requests (11/02/2011) (day has 86.400 seconds)
  • 170. Amount of messages sent to clients since launch (11/02/2011)
  • 171. 35.552.810.379 Amount of messages sent to clients since launch (11/02/2011)
  • 172. average latency (excluding internet - 11/02/2011)
  • 173. < 10ms average latency (excluding internet - 11/02/2011)
  • 176. CGI model is difficult to scale Multi-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  • 177. CGI model is difficult to scale Multi-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  • 178. CGI model is difficult to scale Multi-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  • 179. CGI model is difficult to scale Multi-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  • 180. CGI model is difficult to scale Multi-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  • 181. CGI model is difficult to scale Multi-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  • 182. Ilya Grigorik (igvita)
  • 184. PostRank (acquired by Google!) EM-Synchrony, Goliath Google SPDY research
  • 187. Rev (later Cool.io), Revactor Reia (Ruby syntax over Erlang, replaced by Elixir) Celluloid (Threads abstraction to Actors) (Mark Perham used to create Sidekiq)
  • 188. Ruby is very flexible
  • 190. Browser Browser Browser Browser Browser Browser NginX, HAProxy Passenger, Unicorn
  • 191. Browser Browser Browser Browser Browser Browser NginX, HAProxy JRuby - TorqueBox, Trinidad (multiple concurrent native threads)
  • 193. Native threads Ruby 1.9.x (extensions can release the GIL) Native threads JRuby (no GIL) Native threads Rubinius (no GIL check out the Puma webserver)
  • 194. Native threads Ruby 1.9.x (extensions can release the GIL) Native threads JRuby (no GIL) Native threads Rubinius (no GIL check out the Puma webserver)
  • 195. Native threads Ruby 1.9.x (extensions can release the GIL) Native threads JRuby (no GIL) Native threads Rubinius (no GIL check out the Puma webserver)
  • 199. Большое спасибо www.codeminer.com.br www.akitaonrails.com @akitaonrails