SlideShare a Scribd company logo
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 2010
Ilya Grigorik
 
Real Time Event Dispatcher
Real Time Event DispatcherReal Time Event Dispatcher
Real Time Event Dispatcher
Peter 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 matters
timbc
 
Implementing Comet using PHP
Implementing Comet using PHPImplementing Comet using PHP
Implementing Comet using PHP
King Foo
 
A complete guide to Node.js
A complete guide to Node.jsA complete guide to Node.js
A complete guide to Node.js
Prabin Silwal
 
Ruby Concurrency and EventMachine
Ruby Concurrency and EventMachineRuby Concurrency and EventMachine
Ruby Concurrency and EventMachine
Christopher 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! Framework
Fabio Tiriticco
 
Realtime Streaming using Autobahn Websockets
Realtime Streaming using Autobahn WebsocketsRealtime Streaming using Autobahn Websockets
Realtime Streaming using Autobahn Websockets
Tom Sheffler
 
Speedy TDD with Rails
Speedy TDD with RailsSpeedy TDD with Rails
Speedy TDD with Rails
PatchSpace Ltd
 
Node.js - Advanced Basics
Node.js - Advanced BasicsNode.js - Advanced Basics
Node.js - Advanced Basics
Doug 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 Server
Doug Jones
 
Treasure Data Summer Internship Final Report
Treasure Data Summer Internship Final ReportTreasure Data Summer Internship Final Report
Treasure Data Summer Internship Final Report
Ritta Narita
 
Implement server push in flask framework
Implement server push in flask frameworkImplement server push in flask framework
Implement server push in flask framework
Chi-Chia Huang
 
Lies, Damn Lies, and Benchmarks
Lies, Damn Lies, and BenchmarksLies, Damn Lies, and Benchmarks
Lies, Damn Lies, and Benchmarks
Workhorse Computing
 
Expand Your Testing with Virtual Services
Expand Your Testing with Virtual ServicesExpand Your Testing with Virtual Services
Expand Your Testing with Virtual Services
Amber 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 2015
Masahiro 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 Needs
DigitalOcean
 
Node.js
Node.jsNode.js
Node.js
hotrannam
 
Http capturing
Http capturingHttp capturing
Http capturing
Eric Ahn
 
Comet from JavaOne 2008
Comet from JavaOne 2008Comet from JavaOne 2008
Comet from JavaOne 2008
Joe 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 Communications
Alexei Skachykhin
 
03 sockets
03 sockets03 sockets
03 sockets
Pavan Illa
 
Server architecture
Server architectureServer architecture
Server architecture
Masters Academy
 
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
Wesley 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.docx
hanneloremccaffery
 
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 ease
KAI 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.docx
kacie8xcheco
 
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 + Ballerina
WSO2
 
Rpi python web
Rpi python webRpi python web
Rpi python web
sewoo lee
 
Intro to PSGI and Plack
Intro to PSGI and PlackIntro to PSGI and Plack
Intro to PSGI and Plack
Tatsuhiko Miyagawa
 

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 2012
Ilya Grigorik
 
Ruby in the Browser - RubyConf 2011
Ruby in the Browser - RubyConf 2011Ruby in the Browser - RubyConf 2011
Ruby in the Browser - RubyConf 2011
Ilya 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 Web
Ilya 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 '09
Ilya 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 Ruby
Ilya Grigorik
 
Event Driven Architecture - MeshU - Ilya Grigorik
Event Driven Architecture - MeshU - Ilya GrigorikEvent Driven Architecture - MeshU - Ilya Grigorik
Event Driven Architecture - MeshU - Ilya Grigorik
Ilya Grigorik
 
Taming The RSS Beast
Taming The  RSS  BeastTaming The  RSS  Beast
Taming The RSS Beast
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

FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
Bhaskar Mitra
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 

Recently uploaded (20)

FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 

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.