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

More Related Content

What's hot

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

What's hot (20)

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

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

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

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

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

More from Ilya Grigorik

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

More from Ilya Grigorik (10)

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

Recently uploaded

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
Ā 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(ā˜Žļø+971_581248768%)**%*]'#abortion pills for sale in dubai@
Ā 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
Ā 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
Ā 

Recently uploaded (20)

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
Ā 
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
Ā 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
Ā 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
Ā 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
Ā 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
Ā 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
Ā 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
Ā 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
Ā 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
Ā 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
Ā 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
Ā 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
Ā 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
Ā 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Ā 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Ā 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
Ā 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Ā 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
Ā 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
Ā 

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.