SlideShare a Scribd company logo
1 of 66
Ruby C10K: High Performance Networkinga case study with EM-Proxy Ilya Grigorik @igrigorik
postrank.com/topic/ruby Twitter My blog
C10K  EM-Proxy +  Examples Benchmarks + Misc EventMachine
Proxy Love
“Rails, Django, Seaside, Grails…” cant scale. Myth: Slow Frameworks
The Proxy Solution
The “More” Proxy Solution
Transparent Scalability
Load Balancer Reverse Proxy App Server MySQL Proxy Architecture middleware ftw! Shard 1 Shard 2
C10K Problem + Ruby why do we care?
Bottleneck: ~100 req / s Complexity, Time, and Money circa 1995-2000
Receive Verify Dispatch Aggregate Handle errors Render Send Application  Bottlenecks I/O + Kernel Bottlenecks  Kernel + I/O Bottlenecks
C10K Challenge: 10,000 Concurrent Connections
No concurrency Blocking Ok resource utilization require 'rubygems'require 'socket'server = TCPServer.new(80)loop do    session = server.acceptsession.print"HTTP/1.1 200 OKdone"session.closeend Fork! Synchronous + Blocking IO
Fork Latency Linux 2.6: ~200 microseconds
Socket.accept_nonblock ,[object Object]
Poll for each socketselect( […], nil, nil ) ,[object Object]
Non linear performanceNon-Blocking IO + Poll concurrency without threads
Epoll + Kqueue Benchmarks
while (1) { intnfds = epoll_wait(fd, arr, 3, timeout); if (nfds < 0) die("Error in epoll_wait!"); for(inti = 0; i < nfds; i++) { intfd = events[i].data.fd; handle_io_on_socket(fd);    } } and in Ruby… EPoll & KQueue concurrency without threads require 'eventmachine'EM.epoll EM.run {   # ...}
while (1) { intnfds = epoll_wait(fd, arr, 3, timeout); if (nfds < 0) die("Error in epoll_wait!"); for(inti = 0; i < nfds; i++) { intfd = events[i].data.fd; handle_io_on_socket(fd);    } } and in Ruby… EPoll & KQueue concurrency without threads require 'eventmachine'EM.epoll EM.run { # ...}
EventMachine: Speed + Convenience building high performance network apps in Ruby
p "Starting"EM.run do  p "Running in EM reactor"endputs "Almost done" whiletruedo        timersnetwork_ioother_io end EventMachine Reactor concurrency without threads
p "Starting"EM.rundo  p "Running in EM reactor"endputs "Almost done" whiletruedo timersnetwork_ioother_io end EventMachine Reactor concurrency without threads
C++ core     Easy concurrency without threading EventMachine Reactor concurrency without threads
http = EM::HttpRequest.new('http://site.com/').get http.callback {     p http.response   }  # ... do other work, until callback fires.    Event = IO event + block or lambda call EventMachine Reactor concurrency without threads
http=EM::HttpRequest.new('http://site.com/').get http.callback{ phttp.response } # ... do other work, until callback fires. Screencast:  http://bit.ly/hPr3j    Event = IO event + block or lambda call EventMachine Reactor concurrency without threads
EM.rundoEM.add_timer(1) { p "1 second later" }EM.add_periodic_timer(5) { p "every 5 seconds"}EM.defer { long_running_task() }end class Server < EM::Connection  def receive_data(data)send_data("Pong; #{data}")  end  def unbind    p [:connection_completed]  endend EM.run doEM.start_server "0.0.0.0", 3000, Serverend
EM.run doEM.add_timer(1) { p "1 second later" }EM.add_periodic_timer(5) { p "every 5 seconds"}EM.defer { long_running_task() }end class Server < EM::Connection  def receive_data(data)send_data("Pong; #{data}")  end  def unbind    p [:connection_completed]  endend EM.rundoEM.start_server"0.0.0.0", 3000, Serverend Start Reactor
EM.run doEM.add_timer(1) { p "1 second later" }EM.add_periodic_timer(5) { p "every 5 seconds"}EM.defer { long_running_task() }end class Server < EM::Connectiondefreceive_data(data)send_data("Pong; #{data}")enddef unbind    p [:connection_completed]endend EM.rundoEM.start_server"0.0.0.0", 3000, Serverend Connection Handler Start Reactor
http://bit.ly/aiderss-eventmachine by Dan Sinclair (Twitter: @dj2sincl)
Profile of queries changes	Fail Load on production changes	Fail Parallel environment					Fail Slower release cycle					Fail Problem: Staging Environment Fail
Proxies for Monitoring, Performance and Scalewelcome tothe wonderful world of… (C10K proof)…
Duplex Ruby Proxy, FTW! Real (production) traffic Benchmarking Proxy flash of the obvious
github.com/igrigorik/em-proxy Proxy DSL: EM + EPoll
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:name, :host => "127.0.0.1", :port => 81conn.on_data do |data|    # ...  endconn.on_response do |server, resp|    # ...  endconn.on_finish do    # ...  endend Relay Server EM-Proxy www.github.com/igrigorik/em-proxy
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:name, :host => "127.0.0.1", :port => 81conn.on_datado |data|# ...endconn.on_response do |server, resp|    # ...  endconn.on_finish do    # ...  endend Process incoming data EM-Proxy www.github.com/igrigorik/em-proxy
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:name, :host => "127.0.0.1", :port => 81conn.on_datado |data|# ...endconn.on_responsedo |server, resp|# ...endconn.on_finish do    # ...  endend Process response data EM-Proxy www.github.com/igrigorik/em-proxy
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:name, :host => "127.0.0.1", :port => 81conn.on_datado |data|# ...endconn.on_responsedo |server, resp|# ...endconn.on_finishdo# ...endend Post-processing step EM-Proxy www.github.com/igrigorik/em-proxy
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 81  # modify / process request streamconn.on_data do |data|    p [:on_data, data]    data  end  # modify / process response streamconn.on_response do |server, resp|    p [:on_response, server, resp]resp  end  end Example: Port-Forwarding transparent proxy
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 81# modify / process request streamconn.on_datado |data|    p [:on_data, data]    dataend# modify / process response streamconn.on_response do |server, resp|    p [:on_response, server, resp]resp  end  end Example: Port-Forwarding transparent proxy
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 81# modify / process request streamconn.on_datado |data|    p [:on_data, data]    dataend# modify / process response streamconn.on_responsedo |server, resp|    p [:on_response, server, resp]respendend No data modifications Example: Port-Forwarding transparent proxy
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 81conn.on_datado |data|    dataendconn.on_response do |backend, resp|resp.gsub(/hello/, 'good bye')  endend Example: Port-Forwarding + Alter transparent proxy
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 81conn.on_datado |data|    dataendconn.on_responsedo |backend, resp|resp.gsub(/hello/, 'good bye')endend Alter response Example: Port-Forwarding + Alter transparent proxy
Duplicating HTTP Traffic for benchmarking & monitoring
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|@start = Time.now@data = Hash.new("")conn.server:prod, :host => "127.0.0.1", :port => 81 conn.server:test, :host => "127.0.0.1", :port => 82  conn.on_data do |data|data.gsub(/User-Agent: .*?/, 'User-Agent: em-proxy')  endconn.on_response do |server, resp|    @data[server] += respresp if server == :prod  endconn.on_finish do    p [:on_finish, Time.now - @start]    p @data  endend Prod + Test Duplex HTTP: Benchmarking Intercepting proxy
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|  @start = Time.now  @data = Hash.new("")conn.server :prod, :host => "127.0.0.1", :port => 81 conn.server :test, :host => "127.0.0.1", :port => 82  conn.on_datado |data|data.gsub(/User-Agent: .*?/, 'User-Agent: em-proxy')endconn.on_responsedo |server, resp|@data[server] += resprespif server == :prodendconn.on_finish do    p [:on_finish, Time.now - @start]    p @data  endend Respond from production Duplex HTTP: Benchmarking Intercepting proxy
Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|  @start = Time.now  @data = Hash.new("")conn.server :prod, :host => "127.0.0.1", :port => 81 conn.server :test, :host => "127.0.0.1", :port => 82  conn.on_data do |data|data.gsub(/User-Agent: .*?/, 'User-Agent: em-proxy')  endconn.on_response do |server, resp|    @data[server] += respresp if server == :prod  endconn.on_finishdo    p [:on_finish, Time.now - @start]    p @dataendend Run post-processing Duplex HTTP: Benchmarking Intercepting proxy
[ilya@igvita] >ruby examples/appserver.rb 81 [ilya@igvita] >ruby examples/appserver.rb 82 [ilya@igvita] >ruby examples/line_interceptor.rb [ilya@igvita] >curl localhost >> [:on_finish, 1.008561]>> {:prod=>"HTTP/1.1 200 OKConnection: closeDate: Fri, 01 May 2009 04:20:00 GMTContent-Type: text/plainhello world: 0",       :test=>"HTTP/1.1 200 OKConnection: closeDate: Fri, 01 May 2009 04:20:00 GMTContent-Type: text/plainhello world: 1"} Duplex HTTP: Benchmarking Intercepting proxy
[ilya@igvita] >ruby examples/appserver.rb 81 [ilya@igvita] >ruby examples/appserver.rb 82 [ilya@igvita] >ruby examples/line_interceptor.rb [ilya@igvita] >curl localhost STDOUT [:on_finish, 1.008561]{:prod=>"HTTP/1.1 200 OKConnection: closeDate: Fri, 01 May 2009 04:20:00 GMTContent-Type: text/plainhello world: 0",:test=>"HTTP/1.1 200 OKConnection: closeDate: Fri, 01 May 2009 04:20:00 GMTContent-Type: text/plainhello world: 1"} Duplex HTTP: Benchmarking Intercepting proxy
Same response, different turnaround time Different response body!
Woops! Validating Proxy easy, real-time diagnostics
Hacking SMTP: Whitelisting for fun and profit
Proxy.start(:host => "0.0.0.0", :port => 2524) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 2525# RCPT TO:<name@address.com>  RCPT_CMD = /RCPT TO:<(.*)?>/conn.on_data do |data|    if rcpt = data.match(RCPT_CMD)      if rcpt[1] != "ilya@igvita.com"conn.send_data "550 No such user here"       data = nil      end    end    data  endconn.on_responsedo |backend, resp|respendend Intercept Addressee Defeating SMTP Wildcards Intercepting proxy
Proxy.start(:host => "0.0.0.0", :port => 2524) do |conn|conn.server :srv, :host => "127.0.0.1", :port => 2525  # RCPT TO:<name@address.com>  RCPT_CMD = /RCPT TO:<(.*)?>/conn.on_datado |data|if rcpt = data.match(RCPT_CMD)if rcpt[1] != "ilya@igvita.com"conn.send_data"550 No such user here"       data = nilendend    dataendconn.on_response do |backend, resp|resp  endend Allow: ilya@igvita.com 550 Error otherwise Defeating SMTP Wildcards Intercepting proxy
[ilya@igvita] >mailtrap run –p 2525 –f /tmp/mailtrap.log [ilya@igvita] >ruby examples/smtp_whitelist.rb > require 'net/smtp‘> smtp = Net::SMTP.start("localhost", 2524)> smtp.send_message "Hello World!", "ilya@aiderss.com", "ilya@igvita.com" => #<Net::SMTP::Response:0xb7dcff5c @status="250", @string="250 OK">> smtp.finish => #<Net::SMTP::Response:0xb7dcc8d4 @status="221", @string="221 Seeya">> smtp.send_message "Hello World!", "ilya@aiderss.com", “missing_user@igvita.com" => Net::SMTPFatalError: 550 No such user here Duplex HTTP: Benchmarking Intercepting proxy
[ilya@igvita] >mailtrap run –p 2525 –f /tmp/mailtrap.log [ilya@igvita] >ruby examples/smtp_whitelist.rb To: ilya@igvita.com > require 'net/smtp‘> smtp = Net::SMTP.start("localhost", 2524)> smtp.send_message"Hello World!", "ilya@aiderss.com", "ilya@igvita.com" => #<Net::SMTP::Response:0xb7dcff5c @status="250", @string="250 OK">> smtp.finish => #<Net::SMTP::Response:0xb7dcc8d4 @status="221", @string="221 Seeya">> smtp.send_message"Hello World!", "ilya@aiderss.com", “missing_user@igvita.com" => Net::SMTPFatalError: 550 No such user here Denied! Duplex HTTP: Benchmarking Intercepting proxy
: Beanstalkd + EM-Proxy  because RAM is still expensive
  ~ 93  Bytes of overhead per job ~300   Bytes of data / job    x 80,000,000 jobs in memory     ~ 30 GB of RAM  =  2 X-Large EC2 instances Oi, expensive! BeanstalkdMath
 Observations:  1.  Each job is rescheduled several times    2.  > 95%  are scheduled for > 3 hours into the future    3. Beanstalkd does not have overflow page-to-disk Memory is wasted… Extending Beanstalkd We’ll add it ourselves!
1 “Medium” EC2 Instance Intercepting Proxy @PostRank: “Chronos Scheduler”
Proxy.start(:host => "0.0.0.0", :port => 11300) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 11301  PUT_CMD = /put (+) (+) (+) (+)/conn.on_data do |data|    if put = data.match(PUT_CMD)      if put[2].to_i > 600        p [:put, :archive]        # INSERT INTO ....conn.send_data "INSERTED 9999"        data = nil      end    end    data  endconn.on_responsedo |backend, resp|respendend Intercept PUT command
Proxy.start(:host => "0.0.0.0", :port => 11300) do |conn|conn.server :srv, :host => "127.0.0.1", :port => 11301  PUT_CMD = /put (+) (+) (+) (+)/conn.on_datado |data|if put = data.match(PUT_CMD)if put[2].to_i > 600        p [:put, :archive]# INSERT INTO ....conn.send_data"INSERTED 9999"        data = nilendend    dataendconn.on_response do |backend, resp|resp  endend If over 10 minutes… Archive & Reply
Overload the protocol       PUT put job, 900  RESERVE, PUT, … @PostRank: “Chronos Scheduler”
~79,000,000 jobs, 4GB RAM 400% cheaper + extensible!       PUT Upcoming jobs: ~ 1M RESERVE, PUT, … @PostRank: “Chronos Scheduler”

More Related Content

What's hot

0-60 with Goliath: High performance web services
0-60 with Goliath: High performance web services0-60 with Goliath: High performance web services
0-60 with Goliath: High performance web services
Ilya Grigorik
 
Fast, concurrent ruby web applications with EventMachine and EM::Synchrony
Fast, concurrent ruby web applications with EventMachine and EM::SynchronyFast, concurrent ruby web applications with EventMachine and EM::Synchrony
Fast, concurrent ruby web applications with EventMachine and EM::Synchrony
Kyle Drake
 
Symfony2 Components - The Event Dispatcher
Symfony2 Components - The Event DispatcherSymfony2 Components - The Event Dispatcher
Symfony2 Components - The Event Dispatcher
Sarah El-Atm
 
How Danga::Socket handles asynchronous processing and how to write asynchrono...
How Danga::Socket handles asynchronous processing and how to write asynchrono...How Danga::Socket handles asynchronous processing and how to write asynchrono...
How Danga::Socket handles asynchronous processing and how to write asynchrono...
Gosuke Miyashita
 

What's hot (20)

0-60 with Goliath: High performance web services
0-60 with Goliath: High performance web services0-60 with Goliath: High performance web services
0-60 with Goliath: High performance web services
 
No Callbacks, No Threads - RailsConf 2010
No Callbacks, No Threads - RailsConf 2010No Callbacks, No Threads - RailsConf 2010
No Callbacks, No Threads - RailsConf 2010
 
Real Time Event Dispatcher
Real Time Event DispatcherReal Time Event Dispatcher
Real Time Event Dispatcher
 
Fast, concurrent ruby web applications with EventMachine and EM::Synchrony
Fast, concurrent ruby web applications with EventMachine and EM::SynchronyFast, concurrent ruby web applications with EventMachine and EM::Synchrony
Fast, concurrent ruby web applications with EventMachine and EM::Synchrony
 
Why async matters
Why async mattersWhy async matters
Why async matters
 
Implementing Comet using PHP
Implementing Comet using PHPImplementing Comet using PHP
Implementing Comet using PHP
 
A complete guide to Node.js
A complete guide to Node.jsA complete guide to Node.js
A complete guide to Node.js
 
Ruby Concurrency and EventMachine
Ruby Concurrency and EventMachineRuby Concurrency and EventMachine
Ruby Concurrency and EventMachine
 
Symfony2 Components - The Event Dispatcher
Symfony2 Components - The Event DispatcherSymfony2 Components - The Event Dispatcher
Symfony2 Components - The Event Dispatcher
 
About Node.js
About Node.jsAbout Node.js
About Node.js
 
WebSockets wiith Scala and Play! Framework
WebSockets wiith Scala and Play! FrameworkWebSockets wiith Scala and Play! Framework
WebSockets wiith Scala and Play! Framework
 
Realtime Streaming using Autobahn Websockets
Realtime Streaming using Autobahn WebsocketsRealtime Streaming using Autobahn Websockets
Realtime Streaming using Autobahn Websockets
 
Speedy TDD with Rails
Speedy TDD with RailsSpeedy TDD with Rails
Speedy TDD with Rails
 
Node.js - Advanced Basics
Node.js - Advanced BasicsNode.js - Advanced Basics
Node.js - Advanced Basics
 
How Danga::Socket handles asynchronous processing and how to write asynchrono...
How Danga::Socket handles asynchronous processing and how to write asynchrono...How Danga::Socket handles asynchronous processing and how to write asynchrono...
How Danga::Socket handles asynchronous processing and how to write asynchrono...
 
Async and Await on the Server
Async and Await on the ServerAsync and Await on the Server
Async and Await on the Server
 
Treasure Data Summer Internship Final Report
Treasure Data Summer Internship Final ReportTreasure Data Summer Internship Final Report
Treasure Data Summer Internship Final Report
 
Implement server push in flask framework
Implement server push in flask frameworkImplement server push in flask framework
Implement server push in flask framework
 
Lies, Damn Lies, and Benchmarks
Lies, Damn Lies, and BenchmarksLies, Damn Lies, and Benchmarks
Lies, Damn Lies, and Benchmarks
 
Expand Your Testing with Virtual Services
Expand Your Testing with Virtual ServicesExpand Your Testing with Virtual Services
Expand Your Testing with Virtual Services
 

Similar to Ruby C10K: High Performance Networking - RubyKaigi '09

Real-Time Python Web: Gevent and Socket.io
Real-Time Python Web: Gevent and Socket.ioReal-Time Python Web: Gevent and Socket.io
Real-Time Python Web: Gevent and Socket.io
Rick Copeland
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
Wesley Beary
 
Live Streaming & Server Sent Events
Live Streaming & Server Sent EventsLive Streaming & Server Sent Events
Live Streaming & Server Sent Events
tkramar
 
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
hanneloremccaffery
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparison
Hiroshi Nakamura
 
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docxProject Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
kacie8xcheco
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 

Similar to Ruby C10K: High Performance Networking - RubyKaigi '09 (20)

Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015
 
How to Leverage Go for Your Networking Needs
How to Leverage Go for Your Networking NeedsHow to Leverage Go for Your Networking Needs
How to Leverage Go for Your Networking Needs
 
Node.js
Node.jsNode.js
Node.js
 
Http capturing
Http capturingHttp capturing
Http capturing
 
Comet from JavaOne 2008
Comet from JavaOne 2008Comet from JavaOne 2008
Comet from JavaOne 2008
 
Real-Time Python Web: Gevent and Socket.io
Real-Time Python Web: Gevent and Socket.ioReal-Time Python Web: Gevent and Socket.io
Real-Time Python Web: Gevent and Socket.io
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
 
Web Real-time Communications
Web Real-time CommunicationsWeb Real-time Communications
Web Real-time Communications
 
03 sockets
03 sockets03 sockets
03 sockets
 
Server architecture
Server architectureServer architecture
Server architecture
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
 
Live Streaming & Server Sent Events
Live Streaming & Server Sent EventsLive Streaming & Server Sent Events
Live Streaming & Server Sent Events
 
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparison
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
 
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docxProject Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
[WSO2 Integration Summit Madrid 2019] Integration + Ballerina
[WSO2 Integration Summit Madrid 2019] Integration + Ballerina[WSO2 Integration Summit Madrid 2019] Integration + Ballerina
[WSO2 Integration Summit Madrid 2019] Integration + Ballerina
 
Rpi python web
Rpi python webRpi python web
Rpi python web
 
Intro to PSGI and Plack
Intro to PSGI and PlackIntro to PSGI and Plack
Intro to PSGI and Plack
 

More from Ilya Grigorik

Pagespeed what, why, and how it works
Pagespeed   what, why, and how it worksPagespeed   what, why, and how it works
Pagespeed what, why, and how it works
Ilya Grigorik
 
Intelligent Ruby + Machine Learning
Intelligent Ruby + Machine LearningIntelligent Ruby + Machine Learning
Intelligent Ruby + Machine Learning
Ilya Grigorik
 
Leveraging Social Media - Strategies & Tactics - PostRank
Leveraging Social Media - Strategies & Tactics - PostRankLeveraging Social Media - Strategies & Tactics - PostRank
Leveraging Social Media - Strategies & Tactics - PostRank
Ilya Grigorik
 

More from Ilya Grigorik (10)

Pagespeed what, why, and how it works
Pagespeed   what, why, and how it worksPagespeed   what, why, and how it works
Pagespeed what, why, and how it works
 
Making the web fast(er) - RailsConf 2012
Making the web fast(er) - RailsConf 2012Making the web fast(er) - RailsConf 2012
Making the web fast(er) - RailsConf 2012
 
Ruby in the Browser - RubyConf 2011
Ruby in the Browser - RubyConf 2011Ruby in the Browser - RubyConf 2011
Ruby in the Browser - RubyConf 2011
 
Intelligent Ruby + Machine Learning
Intelligent Ruby + Machine LearningIntelligent Ruby + Machine Learning
Intelligent Ruby + Machine Learning
 
Real-time Ruby for the Real-time Web
Real-time Ruby for the Real-time WebReal-time Ruby for the Real-time Web
Real-time Ruby for the Real-time Web
 
Lean & Mean Tokyo Cabinet Recipes (with Lua) - FutureRuby '09
Lean & Mean Tokyo Cabinet Recipes (with Lua) - FutureRuby '09Lean & Mean Tokyo Cabinet Recipes (with Lua) - FutureRuby '09
Lean & Mean Tokyo Cabinet Recipes (with Lua) - FutureRuby '09
 
Leveraging Social Media - Strategies & Tactics - PostRank
Leveraging Social Media - Strategies & Tactics - PostRankLeveraging Social Media - Strategies & Tactics - PostRank
Leveraging Social Media - Strategies & Tactics - PostRank
 
Building Mini Google in Ruby
Building Mini Google in RubyBuilding Mini Google in Ruby
Building Mini Google in Ruby
 
Event Driven Architecture - MeshU - Ilya Grigorik
Event Driven Architecture - MeshU - Ilya GrigorikEvent Driven Architecture - MeshU - Ilya Grigorik
Event Driven Architecture - MeshU - Ilya Grigorik
 
Taming The RSS Beast
Taming The  RSS  BeastTaming The  RSS  Beast
Taming The RSS Beast
 

Recently uploaded

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 

Recently uploaded (20)

What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 

Ruby C10K: High Performance Networking - RubyKaigi '09

  • 1. Ruby C10K: High Performance Networkinga case study with EM-Proxy Ilya Grigorik @igrigorik
  • 3. C10K EM-Proxy + Examples Benchmarks + Misc EventMachine
  • 5. “Rails, Django, Seaside, Grails…” cant scale. Myth: Slow Frameworks
  • 9. Load Balancer Reverse Proxy App Server MySQL Proxy Architecture middleware ftw! Shard 1 Shard 2
  • 10. C10K Problem + Ruby why do we care?
  • 11. Bottleneck: ~100 req / s Complexity, Time, and Money circa 1995-2000
  • 12. Receive Verify Dispatch Aggregate Handle errors Render Send Application Bottlenecks I/O + Kernel Bottlenecks Kernel + I/O Bottlenecks
  • 13. C10K Challenge: 10,000 Concurrent Connections
  • 14.
  • 15. No concurrency Blocking Ok resource utilization require 'rubygems'require 'socket'server = TCPServer.new(80)loop do session = server.acceptsession.print"HTTP/1.1 200 OKdone"session.closeend Fork! Synchronous + Blocking IO
  • 16. Fork Latency Linux 2.6: ~200 microseconds
  • 17.
  • 18.
  • 19. Non linear performanceNon-Blocking IO + Poll concurrency without threads
  • 20. Epoll + Kqueue Benchmarks
  • 21. while (1) { intnfds = epoll_wait(fd, arr, 3, timeout); if (nfds < 0) die("Error in epoll_wait!"); for(inti = 0; i < nfds; i++) { intfd = events[i].data.fd; handle_io_on_socket(fd); } } and in Ruby… EPoll & KQueue concurrency without threads require 'eventmachine'EM.epoll EM.run { # ...}
  • 22. while (1) { intnfds = epoll_wait(fd, arr, 3, timeout); if (nfds < 0) die("Error in epoll_wait!"); for(inti = 0; i < nfds; i++) { intfd = events[i].data.fd; handle_io_on_socket(fd); } } and in Ruby… EPoll & KQueue concurrency without threads require 'eventmachine'EM.epoll EM.run { # ...}
  • 23. EventMachine: Speed + Convenience building high performance network apps in Ruby
  • 24. p "Starting"EM.run do p "Running in EM reactor"endputs "Almost done" whiletruedo timersnetwork_ioother_io end EventMachine Reactor concurrency without threads
  • 25. p "Starting"EM.rundo p "Running in EM reactor"endputs "Almost done" whiletruedo timersnetwork_ioother_io end EventMachine Reactor concurrency without threads
  • 26. C++ core Easy concurrency without threading EventMachine Reactor concurrency without threads
  • 27. http = EM::HttpRequest.new('http://site.com/').get http.callback { p http.response } # ... do other work, until callback fires. Event = IO event + block or lambda call EventMachine Reactor concurrency without threads
  • 28. http=EM::HttpRequest.new('http://site.com/').get http.callback{ phttp.response } # ... do other work, until callback fires. Screencast: http://bit.ly/hPr3j Event = IO event + block or lambda call EventMachine Reactor concurrency without threads
  • 29. EM.rundoEM.add_timer(1) { p "1 second later" }EM.add_periodic_timer(5) { p "every 5 seconds"}EM.defer { long_running_task() }end class Server < EM::Connection def receive_data(data)send_data("Pong; #{data}") end def unbind p [:connection_completed] endend EM.run doEM.start_server "0.0.0.0", 3000, Serverend
  • 30. EM.run doEM.add_timer(1) { p "1 second later" }EM.add_periodic_timer(5) { p "every 5 seconds"}EM.defer { long_running_task() }end class Server < EM::Connection def receive_data(data)send_data("Pong; #{data}") end def unbind p [:connection_completed] endend EM.rundoEM.start_server"0.0.0.0", 3000, Serverend Start Reactor
  • 31. EM.run doEM.add_timer(1) { p "1 second later" }EM.add_periodic_timer(5) { p "every 5 seconds"}EM.defer { long_running_task() }end class Server < EM::Connectiondefreceive_data(data)send_data("Pong; #{data}")enddef unbind p [:connection_completed]endend EM.rundoEM.start_server"0.0.0.0", 3000, Serverend Connection Handler Start Reactor
  • 32. http://bit.ly/aiderss-eventmachine by Dan Sinclair (Twitter: @dj2sincl)
  • 33. Profile of queries changes Fail Load on production changes Fail Parallel environment Fail Slower release cycle Fail Problem: Staging Environment Fail
  • 34. Proxies for Monitoring, Performance and Scalewelcome tothe wonderful world of… (C10K proof)…
  • 35. Duplex Ruby Proxy, FTW! Real (production) traffic Benchmarking Proxy flash of the obvious
  • 37. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:name, :host => "127.0.0.1", :port => 81conn.on_data do |data| # ... endconn.on_response do |server, resp| # ... endconn.on_finish do # ... endend Relay Server EM-Proxy www.github.com/igrigorik/em-proxy
  • 38. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:name, :host => "127.0.0.1", :port => 81conn.on_datado |data|# ...endconn.on_response do |server, resp| # ... endconn.on_finish do # ... endend Process incoming data EM-Proxy www.github.com/igrigorik/em-proxy
  • 39. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:name, :host => "127.0.0.1", :port => 81conn.on_datado |data|# ...endconn.on_responsedo |server, resp|# ...endconn.on_finish do # ... endend Process response data EM-Proxy www.github.com/igrigorik/em-proxy
  • 40. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:name, :host => "127.0.0.1", :port => 81conn.on_datado |data|# ...endconn.on_responsedo |server, resp|# ...endconn.on_finishdo# ...endend Post-processing step EM-Proxy www.github.com/igrigorik/em-proxy
  • 41. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 81 # modify / process request streamconn.on_data do |data| p [:on_data, data] data end # modify / process response streamconn.on_response do |server, resp| p [:on_response, server, resp]resp end end Example: Port-Forwarding transparent proxy
  • 42. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 81# modify / process request streamconn.on_datado |data| p [:on_data, data] dataend# modify / process response streamconn.on_response do |server, resp| p [:on_response, server, resp]resp end end Example: Port-Forwarding transparent proxy
  • 43. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 81# modify / process request streamconn.on_datado |data| p [:on_data, data] dataend# modify / process response streamconn.on_responsedo |server, resp| p [:on_response, server, resp]respendend No data modifications Example: Port-Forwarding transparent proxy
  • 44. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 81conn.on_datado |data| dataendconn.on_response do |backend, resp|resp.gsub(/hello/, 'good bye') endend Example: Port-Forwarding + Alter transparent proxy
  • 45. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 81conn.on_datado |data| dataendconn.on_responsedo |backend, resp|resp.gsub(/hello/, 'good bye')endend Alter response Example: Port-Forwarding + Alter transparent proxy
  • 46. Duplicating HTTP Traffic for benchmarking & monitoring
  • 47. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn|@start = Time.now@data = Hash.new("")conn.server:prod, :host => "127.0.0.1", :port => 81 conn.server:test, :host => "127.0.0.1", :port => 82 conn.on_data do |data|data.gsub(/User-Agent: .*?/, 'User-Agent: em-proxy') endconn.on_response do |server, resp| @data[server] += respresp if server == :prod endconn.on_finish do p [:on_finish, Time.now - @start] p @data endend Prod + Test Duplex HTTP: Benchmarking Intercepting proxy
  • 48. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn| @start = Time.now @data = Hash.new("")conn.server :prod, :host => "127.0.0.1", :port => 81 conn.server :test, :host => "127.0.0.1", :port => 82 conn.on_datado |data|data.gsub(/User-Agent: .*?/, 'User-Agent: em-proxy')endconn.on_responsedo |server, resp|@data[server] += resprespif server == :prodendconn.on_finish do p [:on_finish, Time.now - @start] p @data endend Respond from production Duplex HTTP: Benchmarking Intercepting proxy
  • 49. Proxy.start(:host => "0.0.0.0", :port => 80) do |conn| @start = Time.now @data = Hash.new("")conn.server :prod, :host => "127.0.0.1", :port => 81 conn.server :test, :host => "127.0.0.1", :port => 82 conn.on_data do |data|data.gsub(/User-Agent: .*?/, 'User-Agent: em-proxy') endconn.on_response do |server, resp| @data[server] += respresp if server == :prod endconn.on_finishdo p [:on_finish, Time.now - @start] p @dataendend Run post-processing Duplex HTTP: Benchmarking Intercepting proxy
  • 50. [ilya@igvita] >ruby examples/appserver.rb 81 [ilya@igvita] >ruby examples/appserver.rb 82 [ilya@igvita] >ruby examples/line_interceptor.rb [ilya@igvita] >curl localhost >> [:on_finish, 1.008561]>> {:prod=>"HTTP/1.1 200 OKConnection: closeDate: Fri, 01 May 2009 04:20:00 GMTContent-Type: text/plainhello world: 0", :test=>"HTTP/1.1 200 OKConnection: closeDate: Fri, 01 May 2009 04:20:00 GMTContent-Type: text/plainhello world: 1"} Duplex HTTP: Benchmarking Intercepting proxy
  • 51. [ilya@igvita] >ruby examples/appserver.rb 81 [ilya@igvita] >ruby examples/appserver.rb 82 [ilya@igvita] >ruby examples/line_interceptor.rb [ilya@igvita] >curl localhost STDOUT [:on_finish, 1.008561]{:prod=>"HTTP/1.1 200 OKConnection: closeDate: Fri, 01 May 2009 04:20:00 GMTContent-Type: text/plainhello world: 0",:test=>"HTTP/1.1 200 OKConnection: closeDate: Fri, 01 May 2009 04:20:00 GMTContent-Type: text/plainhello world: 1"} Duplex HTTP: Benchmarking Intercepting proxy
  • 52. Same response, different turnaround time Different response body!
  • 53. Woops! Validating Proxy easy, real-time diagnostics
  • 54. Hacking SMTP: Whitelisting for fun and profit
  • 55. Proxy.start(:host => "0.0.0.0", :port => 2524) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 2525# RCPT TO:<name@address.com> RCPT_CMD = /RCPT TO:<(.*)?>/conn.on_data do |data| if rcpt = data.match(RCPT_CMD) if rcpt[1] != "ilya@igvita.com"conn.send_data "550 No such user here" data = nil end end data endconn.on_responsedo |backend, resp|respendend Intercept Addressee Defeating SMTP Wildcards Intercepting proxy
  • 56. Proxy.start(:host => "0.0.0.0", :port => 2524) do |conn|conn.server :srv, :host => "127.0.0.1", :port => 2525 # RCPT TO:<name@address.com> RCPT_CMD = /RCPT TO:<(.*)?>/conn.on_datado |data|if rcpt = data.match(RCPT_CMD)if rcpt[1] != "ilya@igvita.com"conn.send_data"550 No such user here" data = nilendend dataendconn.on_response do |backend, resp|resp endend Allow: ilya@igvita.com 550 Error otherwise Defeating SMTP Wildcards Intercepting proxy
  • 57. [ilya@igvita] >mailtrap run –p 2525 –f /tmp/mailtrap.log [ilya@igvita] >ruby examples/smtp_whitelist.rb > require 'net/smtp‘> smtp = Net::SMTP.start("localhost", 2524)> smtp.send_message "Hello World!", "ilya@aiderss.com", "ilya@igvita.com" => #<Net::SMTP::Response:0xb7dcff5c @status="250", @string="250 OK">> smtp.finish => #<Net::SMTP::Response:0xb7dcc8d4 @status="221", @string="221 Seeya">> smtp.send_message "Hello World!", "ilya@aiderss.com", “missing_user@igvita.com" => Net::SMTPFatalError: 550 No such user here Duplex HTTP: Benchmarking Intercepting proxy
  • 58. [ilya@igvita] >mailtrap run –p 2525 –f /tmp/mailtrap.log [ilya@igvita] >ruby examples/smtp_whitelist.rb To: ilya@igvita.com > require 'net/smtp‘> smtp = Net::SMTP.start("localhost", 2524)> smtp.send_message"Hello World!", "ilya@aiderss.com", "ilya@igvita.com" => #<Net::SMTP::Response:0xb7dcff5c @status="250", @string="250 OK">> smtp.finish => #<Net::SMTP::Response:0xb7dcc8d4 @status="221", @string="221 Seeya">> smtp.send_message"Hello World!", "ilya@aiderss.com", “missing_user@igvita.com" => Net::SMTPFatalError: 550 No such user here Denied! Duplex HTTP: Benchmarking Intercepting proxy
  • 59. : Beanstalkd + EM-Proxy because RAM is still expensive
  • 60. ~ 93 Bytes of overhead per job ~300 Bytes of data / job x 80,000,000 jobs in memory ~ 30 GB of RAM = 2 X-Large EC2 instances Oi, expensive! BeanstalkdMath
  • 61. Observations: 1. Each job is rescheduled several times 2. > 95% are scheduled for > 3 hours into the future 3. Beanstalkd does not have overflow page-to-disk Memory is wasted… Extending Beanstalkd We’ll add it ourselves!
  • 62. 1 “Medium” EC2 Instance Intercepting Proxy @PostRank: “Chronos Scheduler”
  • 63. Proxy.start(:host => "0.0.0.0", :port => 11300) do |conn|conn.server:srv, :host => "127.0.0.1", :port => 11301 PUT_CMD = /put (+) (+) (+) (+)/conn.on_data do |data| if put = data.match(PUT_CMD) if put[2].to_i > 600 p [:put, :archive] # INSERT INTO ....conn.send_data "INSERTED 9999" data = nil end end data endconn.on_responsedo |backend, resp|respendend Intercept PUT command
  • 64. Proxy.start(:host => "0.0.0.0", :port => 11300) do |conn|conn.server :srv, :host => "127.0.0.1", :port => 11301 PUT_CMD = /put (+) (+) (+) (+)/conn.on_datado |data|if put = data.match(PUT_CMD)if put[2].to_i > 600 p [:put, :archive]# INSERT INTO ....conn.send_data"INSERTED 9999" data = nilendend dataendconn.on_response do |backend, resp|resp endend If over 10 minutes… Archive & Reply
  • 65. Overload the protocol PUT put job, 900 RESERVE, PUT, … @PostRank: “Chronos Scheduler”
  • 66. ~79,000,000 jobs, 4GB RAM 400% cheaper + extensible! PUT Upcoming jobs: ~ 1M RESERVE, PUT, … @PostRank: “Chronos Scheduler”
  • 67. … x 2,500 1 process / 1 core ~ 5,000 open sockets ~ 1200 req/s EM-Proxy Beanstalkd MySQL 2x EM-Proxy (dual core) C10K Success! Performance: Beanstalk + EM-Proxy is it “C10K proof”?
  • 68. C10K: http://www.kegel.com/c10k.html Code: http://github.com/igrigorik/em-proxy Twitter: @igrigorik Thanks. Questions? Twitter My blog

Editor's Notes

  1. Proxy servers have become a popular solution as a tool for horizontal scalability. Just add more servers, and we’re good!
  2. Proxy servers have become a popular solution as a tool for horizontal scalability. Just add more servers, and we’re good!
  3. More proxy, more better.Like it or not, this is more or less, the current tool of the trade. We love proxy servers!
  4. More proxy, more better.Like it or not, this is more or less, the current tool of the trade. We love proxy servers!
  5. Reading the papers and mailing lists, it is clear that much of the bottlenecks were actually in the operating system. Web servers would reach capacity at several hundred requests/s at most. In fact, it was not unusual for servers to max out at double digit numbers for tasks as simple as serving static files. Of course, the computers were slower as well, but there were a number of performance bottlenecks which needed to be addressed.
  6. In order to even think about this problem, first we have to look at the server. It turns out, if you’re really aiming for high concurrency, than your options are limited.
  7. In order to even think about this problem, first we have to look at the server. It turns out, if you’re really aiming for high concurrency, than your options are limited.
  8. Apache uses the pre-fork model to ‘minimize’ the cost of forking.
  9. Kqueue and it’s younger cousin Epoll have been invented to address the problems with select’s non-linear performance. Instead of scanning each socket, Epoll and Kqueue deliver only the notifications for sockets that can be acted upon. This is done via both kernel and hardware hooks.
  10. Using Epoll from Ruby is way easier than from C. Thankfully, eventmachine maintainers have already done all the work for us.
  11. The reactor design pattern is a concurrent programming pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.
  12. The reactor design pattern is a concurrent programming pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.