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 servicesIlya Grigorik
 
No Callbacks, No Threads - RailsConf 2010
No Callbacks, No Threads - RailsConf 2010No Callbacks, No Threads - RailsConf 2010
No Callbacks, No Threads - RailsConf 2010Ilya Grigorik
 
Real Time Event Dispatcher
Real Time Event DispatcherReal Time Event Dispatcher
Real Time Event DispatcherPeter Dietrich
 
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::SynchronyKyle Drake
 
Why async matters
Why async mattersWhy async matters
Why async matterstimbc
 
Implementing Comet using PHP
Implementing Comet using PHPImplementing Comet using PHP
Implementing Comet using PHPKing Foo
 
A complete guide to Node.js
A complete guide to Node.jsA complete guide to Node.js
A complete guide to Node.jsPrabin Silwal
 
Ruby Concurrency and EventMachine
Ruby Concurrency and EventMachineRuby Concurrency and EventMachine
Ruby Concurrency and EventMachineChristopher Spring
 
Symfony2 Components - The Event Dispatcher
Symfony2 Components - The Event DispatcherSymfony2 Components - The Event Dispatcher
Symfony2 Components - The Event DispatcherSarah El-Atm
 
WebSockets wiith Scala and Play! Framework
WebSockets wiith Scala and Play! FrameworkWebSockets wiith Scala and Play! Framework
WebSockets wiith Scala and Play! FrameworkFabio Tiriticco
 
Realtime Streaming using Autobahn Websockets
Realtime Streaming using Autobahn WebsocketsRealtime Streaming using Autobahn Websockets
Realtime Streaming using Autobahn WebsocketsTom Sheffler
 
Node.js - Advanced Basics
Node.js - Advanced BasicsNode.js - Advanced Basics
Node.js - Advanced BasicsDoug Jones
 
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
 
Async and Await on the Server
Async and Await on the ServerAsync and Await on the Server
Async and Await on the ServerDoug Jones
 
Treasure Data Summer Internship Final Report
Treasure Data Summer Internship Final ReportTreasure Data Summer Internship Final Report
Treasure Data Summer Internship Final ReportRitta Narita
 
Implement server push in flask framework
Implement server push in flask frameworkImplement server push in flask framework
Implement server push in flask frameworkChi-Chia Huang
 
Expand Your Testing with Virtual Services
Expand Your Testing with Virtual ServicesExpand Your Testing with Virtual Services
Expand Your Testing with Virtual ServicesAmber Race
 

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

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 2015Masahiro Nagano
 
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 NeedsDigitalOcean
 
Http capturing
Http capturingHttp capturing
Http capturingEric Ahn
 
Comet from JavaOne 2008
Comet from JavaOne 2008Comet from JavaOne 2008
Comet from JavaOne 2008Joe Walker
 
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.ioRick 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
 
Web Real-time Communications
Web Real-time CommunicationsWeb Real-time Communications
Web Real-time CommunicationsAlexei Skachykhin
 
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 CloudWesley Beary
 
Live Streaming & Server Sent Events
Live Streaming & Server Sent EventsLive Streaming & Server Sent Events
Live Streaming & Server Sent Eventstkramar
 
[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.docxhanneloremccaffery
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparisonHiroshi Nakamura
 
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 easeKAI CHU CHUNG
 
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.docxkacie8xcheco
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
[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 + BallerinaWSO2
 
Rpi python web
Rpi python webRpi python web
Rpi python websewoo lee
 

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 worksIlya Grigorik
 
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 2012Ilya Grigorik
 
Ruby in the Browser - RubyConf 2011
Ruby in the Browser - RubyConf 2011Ruby in the Browser - RubyConf 2011
Ruby in the Browser - RubyConf 2011Ilya Grigorik
 
Intelligent Ruby + Machine Learning
Intelligent Ruby + Machine LearningIntelligent Ruby + Machine Learning
Intelligent Ruby + Machine LearningIlya Grigorik
 
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 WebIlya Grigorik
 
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 '09Ilya Grigorik
 
Leveraging Social Media - Strategies & Tactics - PostRank
Leveraging Social Media - Strategies & Tactics - PostRankLeveraging Social Media - Strategies & Tactics - PostRank
Leveraging Social Media - Strategies & Tactics - PostRankIlya Grigorik
 
Building Mini Google in Ruby
Building Mini Google in RubyBuilding Mini Google in Ruby
Building Mini Google in RubyIlya Grigorik
 
Event Driven Architecture - MeshU - Ilya Grigorik
Event Driven Architecture - MeshU - Ilya GrigorikEvent Driven Architecture - MeshU - Ilya Grigorik
Event Driven Architecture - MeshU - Ilya GrigorikIlya Grigorik
 
Taming The RSS Beast
Taming The  RSS  BeastTaming The  RSS  Beast
Taming The RSS BeastIlya 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

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
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 WorkerThousandEyes
 
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.pptxHampshireHUG
 
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 productivityPrincipled Technologies
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGSujit Pal
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 

Recently uploaded (20)

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
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
 
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
 
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
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAG
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 

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.