“ Genius is the gold in the mine; talent is  the miner who works and brings it out. ” Lady Marguerite Blessington         ...
“ Genius is the gold in the mine; talent is  the miner who works and brings it out. ” Lady Marguerite Blessington         ...
доброе утро
Fabio Akita, Co-Founder @CodeMiner42
“Off-centered software for      off-centered people”       Fabio Akita, Co-Founder @CodeMiner42
Understandingthe Rails Web Modeland Scalability Options
?
rails new app
somethings don’t change
CGI
1 request blocks 1 process
require rubygemsrequire rackclass Test  def call(env)    sleep 1 # on purpose, simulating a blocking operation    [200, {"...
require rubygemsrequire rackclass Test  def call(env)    sleep 1 # on purpose, simulating a blocking operation    [200, {"...
$ rackup config.ru>> Thin web server (v1.3.1 codename Triple Espresso)>> Maximum connections set to 1024>> Listening on 0....
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      1Tim...
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      1Tim...
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      1Tim...
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      1Tim...
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      1Tim...
Browser   Browser   Browser   Browser    Browser   Browser                     NginX, HAProxy                    Passenger...
Optimize
Browser    Browser   Browser    Browser   Browser      Browser                       NginX, HAProxy          Passenger, Un...
Ruby Enterprise Edition 1.8.7    Copy on Write patched (about to be deprecated)         mark and sweep GC    Ruby 1.9.2 (c...
Ruby Enterprise Edition 1.8.7    Copy on Write patched (about to be deprecated)         mark and sweep GC    Ruby 1.9.2 (c...
Ruby Enterprise Edition 1.8.7    Copy on Write patched (about to be deprecated)         mark and sweep GC    Ruby 1.9.2 (c...
Ruby Enterprise Edition 1.8.7    Copy on Write patched (about to be deprecated)         mark and sweep GC    Ruby 1.9.2 (c...
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         ...
Browser   Browser   Browser    Browser               Varnish           NginX, HAProxy          Passenger, Unicorn         ...
Browser   Browser   Browser    Browser               Varnish           NginX, HAProxy          Passenger, Unicorn         ...
Too Long orPeriodic Polling
Notifications and Events in general         Online Gaming     Chatting and Presence    Collaborative ApplicationsAdvanced a...
(function poll(){        $.ajax({ url: "server", success: function(data){          // do something with the received ‘data...
(function poll(){   setTimeout(function(){      $.ajax({ url: "server", success: function(data){        // do something wi...
Cross Frame communication          HTTP Polling (Ajax)Liveconnect (Java applets, Flash socket)             Long Polling   ...
W3C/IETF Standard - RFC 6455                (12/2011)Full duplex persistent communication channel         Less overhead th...
<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(...
Protocol        IE       Firefox      Chrome   Safari    Operahixie-75                                4        5 hixie-76 ...
POLYFILL/FALLBACK     (web-socket-js)
<script type="text/javascript" src="swfobject.js"></script><script type="text/javascript" src="web_socket.js"></script><sc...
<script type="text/javascript" src="swfobject.js"></script><script type="text/javascript" src="web_socket.js"></script><sc...
<script type="text/javascript" src="swfobject.js"></script><script type="text/javascript" src="web_socket.js"></script><sc...
<script type="text/javascript" src="swfobject.js"></script><script type="text/javascript" src="web_socket.js"></script><sc...
<script type="text/javascript" src="swfobject.js"></script><script type="text/javascript" src="web_socket.js"></script><sc...
Client: kind of OKServer: what do do?
Long running requests
Reactor Pattern   (Eventmachine)
synchronous I/Onon-blocking synchronous I/Onon-blocking asynchronous I/0
Wait Events                (I/O, timers)  Main Loop          Notifies Event(main thread)          Handlers
select   poll
select   poll   epoll   kqueue   IOCP
libevent          libevselect       poll   epoll   kqueue   IOCP
Tornado  Twisted  libevent          libevselect       poll   epoll   kqueue   IOCP
Tornado  Twisted           Node.js  libevent           libevselect       poll    epoll    kqueue   IOCP
Tornado           Cool.io  Twisted           Node.js  libevent           libevselect       poll    epoll    kqueue   IOCP
Tornado           Cool.io  Twisted           Node.js  libevent           libev        EventMachineselect       poll    epo...
Tornado           Cool.io            Goliath  Twisted           Node.js             Thin  libevent           libev        ...
require rubygemsrequire rackclass Test  def call(env)    sleep 1 # on purpose, simulating a blocking operation    [200, {"...
require rubygemsrequire rackclass Test  def call(env)    EM.defer do      sleep 1 # CPU bound, throw to thread-pool (cheat...
require rubygemsrequire rackclass Test  def call(env)    EM.defer do      sleep 1 # CPU bound, throw to thread-pool (cheat...
require rubygemsrequire rackclass Test  def call(env)    EM.defer do      sleep 1 # CPU bound, throw to thread-pool (cheat...
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      1Tim...
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      1Tim...
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      1Tim...
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      1Tim...
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      1Tim...
ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>                               ...
ab -n 10 -c 10 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      10T...
Block     Non-Block Total Time    10 sec   0.0001 secRequests per  Second         1       + 8000
Block     Non-Block Total Time    10 sec   0.0001 secRequests per  Second         1       + 8000
Block     Non-Block Total Time    10 sec   0.0001 secRequests per  Second         1       + 8000
“Tick”                      Timers                    #add_timer                 #add_periodic_timer Reactor Loop         ...
require rubygems # or use Bundler.setuprequire eventmachineclass EchoServer < EM::Connection  def receive_data(data)    if...
require rubygems # or use Bundler.setuprequire eventmachineclass EchoServer < EM::Connection  def receive_data(data)    if...
$ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello World
$ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello WorldRepeating: Hello World
$ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello WorldRepeating: Hello World...
$ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello WorldRepeating: Hello World...
$ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello WorldRepeating: Hello World...
$ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello WorldRepeating: Hello World...
require rubygemsrequire eventmachineEM.run do  # ... main reactor loop  EM.stop # stop the main loop and exitend
require rubygemsrequire eventmachineEM.run   do  puts   1  puts   2  puts   3end
$ ruby em.rb123
require rubygemsrequire eventmachineEM.run do  EM.defer do    sleep 3    puts 1  end  EM.add_timer(1) do    puts 2    EM.a...
$ ruby em.rb4231
var http = require(http);http.createServer(function (req, res) {  res.writeHead(200, {Content-Type: text/plain});  res.end...
ab -n 1000 -c 5 http://127.0.0.1:9876/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level:      5T...
require rubygemsrequire rackRack::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:      5T...
Node.js                     Ruby        libev             Eventmachine, Cool.io      Google V8            MRI, JRuby, Rubi...
Node.js                     Ruby        libev             Eventmachine, Cool.io      Google V8            MRI, JRuby, Rubi...
Node.js                     Ruby        libev             Eventmachine, Cool.io      Google V8            MRI, JRuby, Rubi...
Node.js                     Ruby        libev             Eventmachine, Cool.io      Google V8            MRI, JRuby, Rubi...
Node.js                     Ruby        libev             Eventmachine, Cool.io      Google V8            MRI, JRuby, Rubi...
EM-Websocket
require "rubygems"require eventmachinerequire em-websocketconfig = {:host => "0.0.0.0", :port => 8080, :debug => true}EM::...
Caveats in Callback Driven     Development
fs.rename(/tmp/hello, /tmp/world, function (err) {  if (err) throw err;  console.log(renamed complete);});fs.stat(/tmp/wor...
fs.rename(/tmp/hello, /tmp/world, function (err) {  if (err) throw err;  fs.stat(/tmp/world, function (err, stats) {    if...
EM.run do  page = EM::HttpRequest.new(@url1).get  page.errback do    puts "Site is down! terminate?"  end  page.callback d...
“Callback Spaghetti”
Ruby 1.9 Fibersto the rescue!
number_generator = Fiber.new do  start = 0  loop do    start += 1    Fiber.yield(start)  endend
number_generator = Fiber.new do  start = 0  loop do    start += 1    Fiber.yield(start)  endend> number_generator.resume =...
number_generator = Fiber.new do  start = 0  loop do    start += 1    Fiber.yield(start)  endend> number_generator.resume =...
number_generator = Fiber.new do  start = 0  loop do    start += 1    Fiber.yield(start)  endend> number_generator.resume =...
Less expensive than Threads      cooperative vs preemptive multitasking          developer controls scheduling     no need...
Less expensive than Threads      cooperative vs preemptive multitasking          developer controls scheduling     no need...
Less expensive than Threads      cooperative vs preemptive multitasking          developer controls scheduling     no need...
Less expensive than Threads      cooperative vs preemptive multitasking          developer controls scheduling     no need...
Less expensive than Threads      cooperative vs preemptive multitasking          developer controls scheduling     no need...
EM.run do  page = EM::HttpRequest.new(@url1).get  page.errback do    puts "Site is down! terminate?"  end  page.callback d...
page = http_get(@url1)puts "Fetched page: #{page.response_header.status}"if page  page = http_get(@url2)  puts "Fetched pa...
def http_get(url)  f = Fiber.current  http = EM::HttpRequest.new(url).get  http.callback{ f.resume(http) }  http.errback {...
def http_get(url)  f = Fiber.current  http = EM::HttpRequest.new(url).get  http.callback{ f.resume(http) }  http.errback {...
def http_get(url)  f = Fiber.current  http = EM::HttpRequest.new(url).get  http.callback{ f.resume(http) }  http.errback {...
def http_get(url)  f = Fiber.current  http = EM::HttpRequest.new(url).get  http.callback{ f.resume(http) }  http.errback {...
def http_get(url)  f = Fiber.current  http = EM::HttpRequest.new(url).get  http.callback{ f.resume(http) }  http.errback {...
def http_get(url)  f = Fiber.current  http = EM::HttpRequest.new(url).get  http.callback{ f.resume(http) }  http.errback {...
def http_get(url)  f = Fiber.current  http = EM::HttpRequest.new(url).get  http.callback{ f.resume(http) }  http.errback {...
EM-Synchrony
EM.synchrony do  page = EM::HttpRequest.new("http://www.google.com").get  puts "Look Ma! No callbacks! Fetched page: #{pag...
Goliath
require goliathrequire yajlG = Goliath::Rack # don’t to this, just to fit in this slide :-)class Echo < Goliath::API  use ...
$ 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=He...
Web App Server and App Framework         Fully asynchronous using EventmachineLightweight and High Performance (+ 3k req/s...
Recap so far ...
Ruby can using Reactors to massively scale        Good contender to Node.js-style               (getting better)One single...
Pusher
Browser           Persistent                                 connection!                 async  Rails App                 ...
Browser           Persistent                                 connection!                 async  Rails App                 ...
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script><script src="http://js.pusher.com/1...
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script><script src="http://js.pusher.com/1...
require rubygemsrequire pusherPusher.app_id = 14909Pusher.key = 7114e...c318ePusher.secret = 25aa7...3d49c(a..z).each do |...
time ruby pusher_sync.rbreal 0m14.585suser 0m0.583ssys 0m0.105s
require rubygemsrequire pusherrequire eventmachinePusher.app_id = 14909Pusher.key = 7114e...c318ePusher.secret = 25aa7...d...
require rubygemsrequire pusherrequire eventmachinePusher.app_id = 14909Pusher.key = 7114e...c318ePusher.secret = 25aa7...d...
require rubygemsrequire pusherrequire eventmachinePusher.app_id = 14909Pusher.key = 7114e...c318ePusher.secret = 25aa7...d...
time ruby pusher_async.rbreal 0m1.129suser 0m0.649ssys 0m0.063s
pusher.connection.bind(connected, function() {  alert("Youre up!")});pusher.connection.bind(connecting_in, function(delay)...
Private Channels  Encryption AuthenticationPresence Events
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 sentto 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)
< 10msaverage latency (excluding internet - 11/02/2011)
Wrapping up ...
CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors         HTTP 5 WebSockets is hot!           Eve...
CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors         HTTP 5 WebSockets is hot!           Eve...
CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors         HTTP 5 WebSockets is hot!           Eve...
CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors         HTTP 5 WebSockets is hot!           Eve...
CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors         HTTP 5 WebSockets is hot!           Eve...
CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors         HTTP 5 WebSockets is hot!           Eve...
Ilya Grigorik   (igvita)
PostRank (acquired by Google!)    EM-Synchrony, Goliath    Google SPDY research
Tony Arcieri (bascule)
Rev (later Cool.io), Revactor                   Reia(Ruby syntax over Erlang, replaced by Elixir) Celluloid (Threads abstr...
Ruby is very flexible
one more thing ...
Browser   Browser   Browser   Browser    Browser   Browser                     NginX, HAProxy                    Passenger...
Browser   Browser   Browser   Browser    Browser   Browser                     NginX, HAProxy              JRuby - TorqueB...
Native threadsRuby 1.9.x             (extensions can release the GIL)                     Native threads JRuby            ...
Native threadsRuby 1.9.x             (extensions can release the GIL)                     Native threads JRuby            ...
Native threadsRuby 1.9.x             (extensions can release the GIL)                     Native threads JRuby            ...
Большоеспасибо  www.codeminer.com.br  www.akitaonrails.com  @akitaonrails
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
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
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
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
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
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
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
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
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
Toster - Understanding the Rails Web Model and Scalability Options
Toster - Understanding the Rails Web Model and Scalability Options
Upcoming SlideShare
Loading in...5
×

Toster - Understanding the Rails Web Model and Scalability Options

6,461

Published on

In my first time at Russia, I've presented about Reactor Pattern, Eventmachine, WebSocket and the Pusher service as options for when Rails alone is not enough

Published in: Technology
1 Comment
12 Likes
Statistics
Notes
No Downloads
Views
Total Views
6,461
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
46
Comments
1
Likes
12
Embeds 0
No embeds

No notes for slide

Toster - Understanding the Rails Web Model and Scalability Options

  1. 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. 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
  3. 3. доброе утро
  4. 4. Fabio Akita, Co-Founder @CodeMiner42
  5. 5. “Off-centered software for off-centered people” Fabio Akita, Co-Founder @CodeMiner42
  6. 6. Understandingthe Rails Web Modeland Scalability Options
  7. 7. ?
  8. 8. rails new app
  9. 9. somethings don’t change
  10. 10. CGI
  11. 11. 1 request blocks 1 process
  12. 12. require rubygemsrequire rackclass Test def call(env) sleep 1 # on purpose, simulating a blocking operation [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] endendRack::Handler::Thin.run Test.new
  13. 13. require rubygemsrequire rackclass Test def call(env) sleep 1 # on purpose, simulating a blocking operation [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] endendRack::Handler::Thin.run Test.new
  14. 14. $ 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
  15. 15. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 1Time 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...
  16. 16. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 1Time 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...
  17. 17. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 1Time 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...
  18. 18. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 1Time 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...
  19. 19. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 1Time 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...
  20. 20. Browser Browser Browser Browser Browser Browser NginX, HAProxy Passenger, Unicorn
  21. 21. Optimize
  22. 22. Browser Browser Browser Browser Browser Browser NginX, HAProxy Passenger, Unicorn (CoW GC - REE or MRI 2)
  23. 23. 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
  24. 24. 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
  25. 25. 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
  26. 26. 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
  27. 27. Browser Browser Browser Browser NginX, HAProxy Passenger, Unicorn
  28. 28. Browser Browser Browser Browser NginX, HAProxy Passenger, Unicorn Memcached
  29. 29. Browser Browser Browser Browser Varnish NginX, HAProxy Passenger, Unicorn Memcached
  30. 30. Browser Browser Browser Browser Varnish NginX, HAProxy Passenger, Unicorn Resque Memcached
  31. 31. Browser Browser Browser Browser Varnish NginX, HAProxy Passenger, Unicorn Resque Memcached
  32. 32. Too Long orPeriodic Polling
  33. 33. Notifications and Events in general Online Gaming Chatting and Presence Collaborative ApplicationsAdvanced and more Interactive UI
  34. 34. (function poll(){ $.ajax({ url: "server", success: function(data){ // do something with the received ‘data’ //Setup the next poll recursively poll(); }, dataType: "json"});})();
  35. 35. (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);})();
  36. 36. Cross Frame communication HTTP Polling (Ajax)Liveconnect (Java applets, Flash socket) Long Polling Comet & HTTP Streaming (ex. forever frame/chunked encode)
  37. 37. 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)
  38. 38. <script type="text/javascript"> var ws = new WebSocket("ws://example.com:10081/");</script>
  39. 39. <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>
  40. 40. Protocol IE Firefox Chrome Safari Operahixie-75 4 5 hixie-76 4 6 5.0.1 11 hybi-00 (disabled) (disabled)hybi-06 HTML5 Labs devhybi-07 6hybi-09 HTML5 Labshybi-10 IE 10 7 14RFC 6455 11 16
  41. 41. POLYFILL/FALLBACK (web-socket-js)
  42. 42. <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>
  43. 43. <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>
  44. 44. <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>
  45. 45. <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>
  46. 46. <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>
  47. 47. Client: kind of OKServer: what do do?
  48. 48. Long running requests
  49. 49. Reactor Pattern (Eventmachine)
  50. 50. synchronous I/Onon-blocking synchronous I/Onon-blocking asynchronous I/0
  51. 51. Wait Events (I/O, timers) Main Loop Notifies Event(main thread) Handlers
  52. 52. select poll
  53. 53. select poll epoll kqueue IOCP
  54. 54. libevent libevselect poll epoll kqueue IOCP
  55. 55. Tornado Twisted libevent libevselect poll epoll kqueue IOCP
  56. 56. Tornado Twisted Node.js libevent libevselect poll epoll kqueue IOCP
  57. 57. Tornado Cool.io Twisted Node.js libevent libevselect poll epoll kqueue IOCP
  58. 58. Tornado Cool.io Twisted Node.js libevent libev EventMachineselect poll epoll kqueue IOCP
  59. 59. Tornado Cool.io Goliath Twisted Node.js Thin libevent libev EventMachineselect poll epoll kqueue IOCP
  60. 60. require rubygemsrequire rackclass Test def call(env) sleep 1 # on purpose, simulating a blocking operation [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] endendRack::Handler::Thin.run Test.new
  61. 61. require rubygemsrequire rackclass Test def call(env) EM.defer do sleep 1 # CPU bound, throw to thread-pool (cheating) end [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] endendRack::Handler::Thin.run Test.new
  62. 62. require rubygemsrequire rackclass Test def call(env) EM.defer do sleep 1 # CPU bound, throw to thread-pool (cheating) end [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] endendRack::Handler::Thin.run Test.new
  63. 63. require rubygemsrequire rackclass Test def call(env) EM.defer do sleep 1 # CPU bound, throw to thread-pool (cheating) end [200, {"Content-Type" => "text/plain"}, ["Hello World!"]] endendRack::Handler::Thin.run Test.new
  64. 64. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 1Time 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...
  65. 65. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 1Time 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...
  66. 66. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 1Time 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...
  67. 67. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 1Time 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...
  68. 68. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 1Time 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...
  69. 69. ab -n 10 -c 1 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $> #ZOMG!...Concurrency Level: 1Time 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...
  70. 70. ab -n 10 -c 10 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 10Time 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...
  71. 71. Block Non-Block Total Time 10 sec 0.0001 secRequests per Second 1 + 8000
  72. 72. Block Non-Block Total Time 10 sec 0.0001 secRequests per Second 1 + 8000
  73. 73. Block Non-Block Total Time 10 sec 0.0001 secRequests per Second 1 + 8000
  74. 74. “Tick” Timers #add_timer #add_periodic_timer Reactor Loop Blocking Tasks(Eventmachine) #defer #next_tick
  75. 75. require rubygems # or use Bundler.setuprequire eventmachineclass EchoServer < EM::Connection def receive_data(data) if data.strip =~ /[exit|quit]$/i EM.stop else send_data("Repeating: #{data}") end endend
  76. 76. require rubygems # or use Bundler.setuprequire eventmachineclass EchoServer < EM::Connection def receive_data(data) if data.strip =~ /[exit|quit]$/i EM.stop else send_data("Repeating: #{data}") end endendEventMachine.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
  77. 77. $ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello World
  78. 78. $ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello WorldRepeating: Hello World
  79. 79. $ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello WorldRepeating: Hello WorldPlay again, Sam
  80. 80. $ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello WorldRepeating: Hello WorldPlay again, SamRepeating: Play again, Sam
  81. 81. $ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello WorldRepeating: Hello WorldPlay again, SamRepeating: Play again, Samquit.
  82. 82. $ telnet localhost 10000Trying 127.0.0.1...Connected to localhost.Escape character is ^].Hello WorldRepeating: Hello WorldPlay again, SamRepeating: Play again, SamquitConnection closed by foreign host.
  83. 83. require rubygemsrequire eventmachineEM.run do # ... main reactor loop EM.stop # stop the main loop and exitend
  84. 84. require rubygemsrequire eventmachineEM.run do puts 1 puts 2 puts 3end
  85. 85. $ ruby em.rb123
  86. 86. require rubygemsrequire eventmachineEM.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 4end
  87. 87. $ ruby em.rb4231
  88. 88. var http = require(http);http.createServer(function (req, res) { res.writeHead(200, {Content-Type: text/plain}); res.end(Hello World);}).listen(9876);
  89. 89. ab -n 1000 -c 5 http://127.0.0.1:9876/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 5Time 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...
  90. 90. require rubygemsrequire rackRack::Handler::Thin.run Proc.new { [200, {"Content-Type" => "text/plain"}, ["Hello World!"]]}
  91. 91. ab -n 1000 -c 5 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 <$Revision: 1178079 $>...Concurrency Level: 5Time 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...
  92. 92. Node.js Ruby libev Eventmachine, Cool.io Google V8 MRI, JRuby, RubiniusLess Resources, Faster More Resources, Slightly Processing slower processing callbacks only Threads, Fibers, Callbacks
  93. 93. Node.js Ruby libev Eventmachine, Cool.io Google V8 MRI, JRuby, RubiniusLess Resources, Faster More Resources, Slightly Processing slower processing callbacks only Threads, Fibers, Callbacks
  94. 94. Node.js Ruby libev Eventmachine, Cool.io Google V8 MRI, JRuby, RubiniusLess Resources, Faster More Resources, Slightly Processing slower processing callbacks only Threads, Fibers, Callbacks
  95. 95. Node.js Ruby libev Eventmachine, Cool.io Google V8 MRI, JRuby, RubiniusLess Resources, Faster More Resources, Slightly Processing slower processing callbacks only Threads, Fibers, Callbacks
  96. 96. Node.js Ruby libev Eventmachine, Cool.io Google V8 MRI, JRuby, RubiniusLess Resources, Faster More Resources, Slightly Processing slower processing callbacks only Threads, Fibers, Callbacks
  97. 97. EM-Websocket
  98. 98. require "rubygems"require eventmachinerequire em-websocketconfig = {: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
  99. 99. Caveats in Callback Driven Development
  100. 100. 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));});
  101. 101. 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)); });});
  102. 102. 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 endend
  103. 103. “Callback Spaghetti”
  104. 104. Ruby 1.9 Fibersto the rescue!
  105. 105. number_generator = Fiber.new do start = 0 loop do start += 1 Fiber.yield(start) endend
  106. 106. number_generator = Fiber.new do start = 0 loop do start += 1 Fiber.yield(start) endend> number_generator.resume => 1
  107. 107. number_generator = Fiber.new do start = 0 loop do start += 1 Fiber.yield(start) endend> number_generator.resume => 1> number_generator.resume => 2
  108. 108. number_generator = Fiber.new do start = 0 loop do start += 1 Fiber.yield(start) endend> number_generator.resume => 1> number_generator.resume => 2> number_generator.resume => 3
  109. 109. Less expensive than Threads cooperative vs preemptive multitasking developer controls scheduling no need to have mutexes, no shared datacoroutines / can be implemented with continuations
  110. 110. Less expensive than Threads cooperative vs preemptive multitasking developer controls scheduling no need to have mutexes, no shared datacoroutines / can be implemented with continuations
  111. 111. Less expensive than Threads cooperative vs preemptive multitasking developer controls scheduling no need to have mutexes, no shared datacoroutines / can be implemented with continuations
  112. 112. Less expensive than Threads cooperative vs preemptive multitasking developer controls scheduling no need to have mutexes, no shared datacoroutines / can be implemented with continuations
  113. 113. Less expensive than Threads cooperative vs preemptive multitasking developer controls scheduling no need to have mutexes, no shared datacoroutines / can be implemented with continuations
  114. 114. 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 endend
  115. 115. 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
  116. 116. 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.yieldendEM.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.resumeend
  117. 117. 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.yieldendEM.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.resumeend
  118. 118. 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.yieldendEM.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.resumeend
  119. 119. 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.yieldendEM.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.resumeend
  120. 120. 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.yieldendEM.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.resumeend
  121. 121. 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.yieldendEM.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.resumeend
  122. 122. 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.yieldendEM.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.resumeend
  123. 123. EM-Synchrony
  124. 124. EM.synchrony do page = EM::HttpRequest.new("http://www.google.com").get puts "Look Ma! No callbacks! Fetched page: #{page}" EM.stopend# old wayEM.run do page = EM::HttpRequest.new("http://www.google.com").get page.callback do puts "Lame ... Fetched page: #{page}" EM.stop endend
  125. 125. Goliath
  126. 126. require goliathrequire yajlG = 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] endend
  127. 127. $ ruby echo.rb -p 9001
  128. 128. $ ruby echo.rb -p 9001$ curl http://localhost:9001/{"error":"Echo identifier missing"}
  129. 129. $ ruby echo.rb -p 9001$ curl http://localhost:9001/{"error":"Echo identifier missing"}$ curl http://localhost:9001?echo=Hello%20World{"response":"Hello World"}
  130. 130. Web App Server and App Framework Fully asynchronous using EventmachineLightweight and High Performance (+ 3k req/s in 1 process) Rack aware (but not 100% Rack compatible) Fibers with EM-Synchrony for easier development
  131. 131. Recap so far ...
  132. 132. 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
  133. 133. Pusher
  134. 134. Browser Persistent connection! async Rails App Eventmachine AppResque Queues sync
  135. 135. Browser Persistent connection! async Rails App Eventmachine AppResque Queues sync
  136. 136. <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>
  137. 137. <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>
  138. 138. require rubygemsrequire pusherPusher.app_id = 14909Pusher.key = 7114e...c318ePusher.secret = 25aa7...3d49c(a..z).each do |letter| doc = { :elem_id => letter, :value => "Letter: #{letter}"} Pusher[demo-channel].trigger(create, doc)end
  139. 139. time ruby pusher_sync.rbreal 0m14.585suser 0m0.583ssys 0m0.105s
  140. 140. require rubygemsrequire pusherrequire eventmachinePusher.app_id = 14909Pusher.key = 7114e...c318ePusher.secret = 25aa7...d49cEM.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 endend
  141. 141. require rubygemsrequire pusherrequire eventmachinePusher.app_id = 14909Pusher.key = 7114e...c318ePusher.secret = 25aa7...d49cEM.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 endend
  142. 142. require rubygemsrequire pusherrequire eventmachinePusher.app_id = 14909Pusher.key = 7114e...c318ePusher.secret = 25aa7...d49cEM.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 endend
  143. 143. time ruby pusher_async.rbreal 0m1.129suser 0m0.649ssys 0m0.063s
  144. 144. pusher.connection.bind(connected, function() { alert("Youre up!")});pusher.connection.bind(connecting_in, function(delay) { alert("Retrying in " + delay + " seconds.")});pusher.connection.bind(failed, function() { document.write("Not able to connect.")});
  145. 145. Private Channels Encryption AuthenticationPresence Events
  146. 146. Total API requests (11/02/2011) (day has 86.400 seconds)
  147. 147. 13.969.264 Total API requests (11/02/2011) (day has 86.400 seconds)
  148. 148. Amount of messages sentto clients since launch (11/02/2011)
  149. 149. 35.552.810.379 Amount of messages sent to clients since launch (11/02/2011)
  150. 150. average latency (excluding internet - 11/02/2011)
  151. 151. < 10msaverage latency (excluding internet - 11/02/2011)
  152. 152. Wrapping up ...
  153. 153. CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  154. 154. CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  155. 155. CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  156. 156. CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  157. 157. CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  158. 158. CGI model is difficult to scaleMulti-processes vs multi-threads vs Reactors HTTP 5 WebSockets is hot! Eventmachine is great! Fibers vs “callback spaghetti” Try out Pusher!
  159. 159. Ilya Grigorik (igvita)
  160. 160. PostRank (acquired by Google!) EM-Synchrony, Goliath Google SPDY research
  161. 161. Tony Arcieri (bascule)
  162. 162. Rev (later Cool.io), Revactor Reia(Ruby syntax over Erlang, replaced by Elixir) Celluloid (Threads abstraction to Actors) (Mark Perham used to create Sidekiq)
  163. 163. Ruby is very flexible
  164. 164. one more thing ...
  165. 165. Browser Browser Browser Browser Browser Browser NginX, HAProxy Passenger, Unicorn
  166. 166. Browser Browser Browser Browser Browser Browser NginX, HAProxy JRuby - TorqueBox, Trinidad (multiple concurrent native threads)
  167. 167. Native threadsRuby 1.9.x (extensions can release the GIL) Native threads JRuby (no GIL) Native threadsRubinius (no GIL check out the Puma webserver)
  168. 168. Native threadsRuby 1.9.x (extensions can release the GIL) Native threads JRuby (no GIL) Native threadsRubinius (no GIL check out the Puma webserver)
  169. 169. Native threadsRuby 1.9.x (extensions can release the GIL) Native threads JRuby (no GIL) Native threadsRubinius (no GIL check out the Puma webserver)
  170. 170. Большоеспасибо www.codeminer.com.br www.akitaonrails.com @akitaonrails
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×