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

Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 

Recently uploaded (20)

Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 

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.