SlideShare a Scribd company logo
1 of 67
Ruby Proxies for Scale, Performance
    and Monitoring

                                                                            Ilya Grigorik
                                                                                      @igrigorik



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
postrank.com/topic/ruby




                              The slides…                         Twitter                           My blog


Ruby Proxies + EventMachine       http://bit.ly/railsconf-proxy             @igrigorik #railsconf
Code + Examples                                           EventMachine




                     Misc                                           Proxies

Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy Love



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
“Rails, Django, Seaside, Grails…” cant scale.




                                              Myth: Slow Frameworks



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
The Proxy Solution



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy      @igrigorik #railsconf
The “More” Proxy Solution



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Transparent Scalability



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
Load Balancer

                                                       Reverse Proxy                      App Server




                                   MySQL Proxy



                                                                    Proxy as Middleware
                                                                                          middleware ftw!




Ruby Proxies + EventMachine         http://bit.ly/railsconf-proxy        @igrigorik #railsconf
90% use case


                        %w*Transparent Intercepting Caching …+
                                                                  There are many different types!




Ruby Proxies + EventMachine       http://bit.ly/railsconf-proxy          @igrigorik #railsconf
Transparent
                                                              HAProxy




                              App server A                        App server B




                              Transparent, Cut-Through Proxy



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy        @igrigorik #railsconf
Transparent Proxy = Scalability Power Tool



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy                                                               Proxy




        App server A            App server B                             App server C




                                               Problem: Staging Environment
          Production




Ruby Proxies + EventMachine              http://bit.ly/railsconf-proxy    @igrigorik #railsconf
Simulating traffic?

                                                              Proxy

        Duplication




                                   App server C




                              “Representative Load / Staging”



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy           @igrigorik #railsconf
github.com/igrigorik/autoperf



                                                              Replay log data, rinse, repeat



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy        @igrigorik #railsconf
Profile of queries has changed                                              Fail
          Load on production has changed                                              Fail
          Parallel environment                                                        Fail
          Slower release cycle                                                        Fail




                                                                   Staging fail.



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Duplex Ruby Proxy, FTW!

                                                                      Production




     Real (production) traffic
                                                                     Benchmark




                                                                   Benchmarking Proxy
                                                                                 flash of the obvious




Ruby Proxies + EventMachine        http://bit.ly/railsconf-proxy         @igrigorik #railsconf
github.com/igrigorik/em-proxy
         Proxy DSL FTW!




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
EventMachine: Speed + Convenience
                                  building high performance network apps in Ruby




Ruby Proxies + EventMachine       http://bit.ly/railsconf-proxy   @igrigorik #railsconf
p quot;Startingquot;
                                 while true do
                                                               EM.run do
                                   timers
                                                                p quot;Running in EM reactorquot;
                                   network_io
                                                               end
                                   other_io
                                 end
                                                               puts quot;Almost donequot;




                                                         EventMachine Reactor
                                                              concurrency without threads




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy       @igrigorik #railsconf
p quot;Startingquot;
                                 while true do
                                                              EM.run do
                                   timers
                                                               p quot;Running in EM reactorquot;
                                   network_io
                                                              end
                                   other_io
                                 end
                                                              puts quot;Almost donequot;


                                                         EventMachine Reactor
                                                              concurrency without threads




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy       @igrigorik #railsconf
C++ core


                                         Easy concurrency
                                         without threading




                                                         EventMachine Reactor
                                                              concurrency without threads




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy       @igrigorik #railsconf
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




Ruby Proxies + EventMachine    http://bit.ly/railsconf-proxy       @igrigorik #railsconf
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




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy       @igrigorik #railsconf
EM.run do
         EM.add_timer(1) { p quot;1 second laterquot; }
         EM.add_periodic_timer(5) { p quot;every 5 secondsquot;}
         EM.defer { long_running_task() }
        end


        class Server < EM::Connection
          def receive_data(data)
           send_data(quot;Pong; #{data}quot;)
          end

         def unbind
          p [:connection_completed]
         end
        end


        EM.run do
         EM.start_server quot;0.0.0.0quot;, 3000, Server
        end




Ruby Proxies + EventMachine    http://bit.ly/railsconf-proxy   @igrigorik #railsconf
EM.run do
         EM.add_timer(1) { p quot;1 second laterquot; }
         EM.add_periodic_timer(5) { p quot;every 5 secondsquot;}
         EM.defer { long_running_task() }
        end


        class Server < EM::Connection
          def receive_data(data)
           send_data(quot;Pong; #{data}quot;)                          Connection Handler
          end

         def unbind
          p [:connection_completed]
         end
        end


        EM.run do                                                    Start Reactor
         EM.start_server quot;0.0.0.0quot;, 3000, Server
        end




Ruby Proxies + EventMachine    http://bit.ly/railsconf-proxy   @igrigorik #railsconf
http://bit.ly/aiderss-eventmachine
                              by Dan Sinclair (Twitter: @dj2sincl)



Ruby Proxies + EventMachine         http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxies for Monitoring, Performance and Scale
                                                    welcome to the wonderful world of…




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn|
      conn.server :name, :host => quot;127.0.0.1quot;, :port => 81

       conn.on_data do |data|
        # ...
       end
                                                                         Relay Server
       conn.on_response do |server, resp|
        # ...
       end

      conn.on_finish do
       # ...
      end
     end

                                                                               EM-Proxy
                                                  www.github.com/igrigorik/em-proxy




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn|
      conn.server :name, :host => quot;127.0.0.1quot;, :port => 81

       conn.on_data do |data|
        # ...
       end
                                                                 Process incoming data
       conn.on_response do |server, resp|
        # ...
       end

      conn.on_finish do
       # ...
      end
     end

                                                                               EM-Proxy
                                                  www.github.com/igrigorik/em-proxy




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn|
      conn.server :name, :host => quot;127.0.0.1quot;, :port => 81

       conn.on_data do |data|
        # ...
       end
                                                                 Process response data
       conn.on_response do |server, resp|
        # ...
       end

      conn.on_finish do
       # ...
      end
     end

                                                                               EM-Proxy
                                                  www.github.com/igrigorik/em-proxy




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn|
      conn.server :name, :host => quot;127.0.0.1quot;, :port => 81

       conn.on_data do |data|
        # ...
       end

       conn.on_response do |server, resp|
        # ...
       end
                                                                   Post-processing step
      conn.on_finish do
       # ...
      end
     end

                                                                               EM-Proxy
                                                  www.github.com/igrigorik/em-proxy




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
%w[ <Transparent> Intercepting Caching … +
                                                              solution for every problem




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn|
      conn.server :srv, :host => quot;127.0.0.1quot;, :port => 81

       # modify / process request stream
       conn.on_data do |data|
        p [:on_data, data]
        data
       end                                                       No data modifications

      # modify / process response stream
      conn.on_response do |server, resp|
       p [:on_response, server, resp]
       resp
      end
     end

                                                              Port-Forwarding
                                                                         transparent proxy




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn|
      conn.server :srv, :host => quot;127.0.0.1quot;, :port => 81

       conn.on_data do |data|
        data
       end

      conn.on_response do |backend, resp|                               Alter response
       resp.gsub(/hello/, 'good bye')
      end
     end



                                                      Port-Forwarding + Alter
                                                                         transparent proxy




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
%w[ Transparent <Intercepting> Caching … +
                                                              solution for every problem




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn|
  @start = Time.now
  @data = Hash.new(quot;quot;)

                                                                                 Prod + Test
  conn.server :prod, :host => quot;127.0.0.1quot;, :port => 81
  conn.server :test, :host => quot;127.0.0.1quot;, :port => 82

  conn.on_data do |data|
   data.gsub(/User-Agent: .*?rn/, 'User-Agent: em-proxyrn')
  end

  conn.on_response do |server, resp|
   @data[server] += resp
   resp if server == :prod
  end

  conn.on_finish do
   p [:on_finish, Time.now - @start]
   p @data
  end
 end
                                       Duplex HTTP: Benchmarking
                                                                        Intercepting proxy



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn|
  @start = Time.now
  @data = Hash.new(quot;quot;)

  conn.server :prod, :host => quot;127.0.0.1quot;, :port => 81
  conn.server :test, :host => quot;127.0.0.1quot;, :port => 82

  conn.on_data do |data|
   data.gsub(/User-Agent: .*?rn/, 'User-Agent: em-proxyrn')
  end

  conn.on_response do |server, resp|
                                                              Respond from production
   @data[server] += resp
   resp if server == :prod
  end

  conn.on_finish do
   p [:on_finish, Time.now - @start]
   p @data
  end
 end
                                       Duplex HTTP: Benchmarking
                                                                        Intercepting proxy



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn|
  @start = Time.now
  @data = Hash.new(quot;quot;)

  conn.server :prod, :host => quot;127.0.0.1quot;, :port => 81
  conn.server :test, :host => quot;127.0.0.1quot;, :port => 82

  conn.on_data do |data|
   data.gsub(/User-Agent: .*?rn/, 'User-Agent: em-proxyrn')
  end

  conn.on_response do |server, resp|
   @data[server] += resp
   resp if server == :prod
  end
                                                              Run post-processing
  conn.on_finish do
   p [:on_finish, Time.now - @start]
   p @data
  end
 end
                                       Duplex HTTP: Benchmarking
                                                                        Intercepting proxy



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
[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=>quot;HTTP/1.1 200 OKrnConnection: closernDate: Fri, 01 May 2009
 04:20:00 GMTrnContent-Type: text/plainrnrnhello world: 0quot;,

     :test=>quot;HTTP/1.1 200 OKrnConnection: closernDate: Fri, 01 May 2009
 04:20:00 GMTrnContent-Type: text/plainrnrnhello world: 1quot;}




                                           Duplex HTTP: Benchmarking
                                                                            Intercepting proxy



Ruby Proxies + EventMachine       http://bit.ly/railsconf-proxy   @igrigorik #railsconf
[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=>quot;HTTP/1.1 200 OKrnConnection: closernDate: Fri,
 01 May 2009 04:20:00 GMTrnContent-Type:
 text/plainrnrnhello world: 0quot;,

   :test=>quot;HTTP/1.1 200 OKrnConnection: closernDate: Fri,
 01 May 2009 04:20:00 GMTrnContent-Type:
 text/plainrnrnhello world: 1quot;}

                                           Duplex HTTP: Benchmarking
                                                                            Intercepting proxy



Ruby Proxies + EventMachine       http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Same response, different
                                                                    turnaround time




                                                               Different response body!




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Woops!




                                                              Validating Proxy
                                                              easy, real-time diagnostics




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Hacking SMTP
                                                                          for fun and profit




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 2524) do |conn|
  conn.server :srv, :host => quot;127.0.0.1quot;, :port => 2525

  # RCPT TO:<name@address.com>rn
  RCPT_CMD = /RCPT TO:<(.*)?>rn/
                                                                 Intercept Addressee
  conn.on_data do |data|

    if rcpt = data.match(RCPT_CMD)
      if rcpt[1] != quot;ilya@igvita.comquot;
       conn.send_data quot;550 No such user herenquot;
       data = nil
      end
    end

   data
  end

  conn.on_response do |backend, resp|
   resp
  end
                                             Defeating SMTP Wildcards
 end
                                                                        Intercepting proxy



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 2524) do |conn|
  conn.server :srv, :host => quot;127.0.0.1quot;, :port => 2525

  # RCPT TO:<name@address.com>rn
  RCPT_CMD = /RCPT TO:<(.*)?>rn/

  conn.on_data do |data|
                                                              Allow: ilya@igvita.com
    if rcpt = data.match(RCPT_CMD)
      if rcpt[1] != quot;ilya@igvita.comquot;
       conn.send_data quot;550 No such user herenquot;
       data = nil                                              550 Error otherwise
      end
    end

   data
  end

  conn.on_response do |backend, resp|
   resp
  end
                                             Defeating SMTP Wildcards
 end
                                                                         Intercepting proxy



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy    @igrigorik #railsconf
[ilya@igvita] > mailtrap run –p 2525 –f /tmp/mailtrap.log
 [ilya@igvita] > ruby examples/smtp_whitelist.rb



  > require 'net/smtp‘
  > smtp = Net::SMTP.start(quot;localhostquot;, 2524)
  > smtp.send_message quot;Hello World!quot;, quot;ilya@aiderss.comquot;, quot;ilya@igvita.comquot;
  => #<Net::SMTP::Response:0xb7dcff5c @status=quot;250quot;, @string=quot;250 OKnquot;>
  > smtp.finish
  => #<Net::SMTP::Response:0xb7dcc8d4 @status=quot;221quot;, @string=quot;221 Seeyanquot;>

  > smtp.send_message quot;Hello World!quot;, quot;ilya@aiderss.comquot;, “missing_user@igvita.comquot;
  => Net::SMTPFatalError: 550 No such user here




                                         Duplex HTTP: Benchmarking
                                                                          Intercepting proxy



Ruby Proxies + EventMachine     http://bit.ly/railsconf-proxy   @igrigorik #railsconf
[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(quot;localhostquot;, 2524)

  > smtp.send_message quot;Hello World!quot;, quot;ilya@aiderss.comquot;, quot;ilya@igvita.comquot;
  => #<Net::SMTP::Response:0xb7dcff5c @status=quot;250quot;, @string=quot;250 OKnquot;>

  > smtp.finish
  => #<Net::SMTP::Response:0xb7dcc8d4 @status=quot;221quot;, @string=quot;221 Seeyanquot;>

  > smtp.send_message quot;Hello World!quot;, quot;ilya@aiderss.comquot;, “missing_user@igvita.comquot;
  => Net::SMTPFatalError: 550 No such user here

                                                                                       Denied!


                                              Duplex HTTP: Benchmarking
                                                                               Intercepting proxy



Ruby Proxies + EventMachine          http://bit.ly/railsconf-proxy   @igrigorik #railsconf
“Hacking SMTP”.gsub(/Hacking/, ’Kung-fu’)
                                                              DIY spam filtering with Defensio




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy           @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 2524) do |conn|
  conn.server :srv, :host => quot;127.0.0.1quot;, :port => 2525

  RCPT_CMD = /RCPT TO:<(.*)?>rn/
  FROM_CMD = /MAIL FROM:<(.*)?>rn/
  MSG_CMD = /354 Start your message/
  MSGEND_CMD = /^.rn/                                            Intercept commands

  conn.on_data do |data|
   #…
  end

  conn.on_response do |server, resp|
   p [:resp, resp]

    if resp.match(MSG_CMD)
      @buffer = true
      @msg = quot;quot;
    end

   resp
                                                         SMTP + SPAM Filtering
  end
 end
                                                               building a state-machine



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 2524) do |conn|
  conn.server :srv, :host => quot;127.0.0.1quot;, :port => 2525

  RCPT_CMD = /RCPT TO:<(.*)?>rn/
  FROM_CMD = /MAIL FROM:<(.*)?>rn/
  MSG_CMD = /354 Start your message/
  MSGEND_CMD = /^.rn/

  conn.on_data do |data|
   #…
  end

  conn.on_response do |server, resp|
   p [:resp, resp]

    if resp.match(MSG_CMD)                                       Flag & Buffer message
      @buffer = true
      @msg = quot;quot;
    end

   resp
                                                         SMTP + SPAM Filtering
  end
 end
                                                               building a state-machine



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
Save data

 conn.on_data do |data|
   @from = data.match(FROM_CMD)[1] if data.match(FROM_CMD)
   @rcpt = data.match(RCPT_CMD)[1] if data.match(RCPT_CMD)
   @done = true if data.match(MSGEND_CMD)

    if @buffer
      @msg += data
                                                     Buffer
      data = nil
    end

    if @done
     #…
    end

   data
                                                         SMTP + SPAM Filtering
  end
                                                               building a state-machine



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
conn.on_data do |data|
   @from = data.match(FROM_CMD)[1] if data.match(FROM_CMD)
   @rcpt = data.match(RCPT_CMD)[1] if data.match(RCPT_CMD)
   @done = true if data.match(MSGEND_CMD)

    if @buffer
      @msg += data
                                        Flag end of message
      data = nil
    end

    if @done
     #…                                    Process message
    end

   data
                                                         SMTP + SPAM Filtering
  end
                                                               building a state-machine



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
@buffer = false
 uri = URI.parse('http://api.defensio.com/app/1.2/audit/key.yaml')
 res = Net::HTTP.post_form(uri, {
       quot;owner-urlquot; => quot;http://www.github.com/igrigorik/em-proxyquot;,
       quot;user-ipquot; => quot;216.16.254.254quot;,
       quot;article-datequot; => quot;2009/05/01quot;,
       quot;comment-authorquot; => @from,
                                                       Defensio API
       quot;comment-typequot; => quot;commentquot;,
       quot;comment-contentquot; => @msg})

      defensio = YAML.load(res.body)['defensio-result']
      p [:defensio, quot;SPAM: #{defensio['spam']}quot;]

      if defensio['spam']
        conn.send_data quot;550 No such user herenquot;
      else
        data = @msg
      end

                                                         SMTP + SPAM Filtering
                                                               building a state-machine



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
@buffer = false
 uri = URI.parse('http://api.defensio.com/app/1.2/audit/key.yaml')
 res = Net::HTTP.post_form(uri, {
       quot;owner-urlquot; => quot;http://www.github.com/igrigorik/em-proxyquot;,
       quot;user-ipquot; => quot;216.16.254.254quot;,
       quot;article-datequot; => quot;2009/05/01quot;,
       quot;comment-authorquot; => @from,
       quot;comment-typequot; => quot;commentquot;,
       quot;comment-contentquot; => @msg})

      defensio = YAML.load(res.body)['defensio-result']
      p [:defensio, quot;SPAM: #{defensio['spam']}quot;]

      if defensio['spam']
                                                                          Pass / Deny Message
        conn.send_data quot;550 No such user herenquot;
      else
        data = @msg
      end

                                                         SMTP + SPAM Filtering
                                                               building a state-machine



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
Protocol Trace


   [:relay_from_backend, :srv, quot;354 Start your messagequot;]
   [:resp, quot;354 Start your messagequot;]
   [:srv, quot;nquot;]
   [:relay_from_backend, :srv, quot;nquot;]
   [:resp, quot;nquot;]
   [:connection, quot;Hello Worldrnquot;]
   [:connection, quot;.rnquot;]
   [:defensio, quot;SPAM: false, Spaminess: 0.4quot;]
   [:srv, quot;250 OKnquot;]
   [:relay_from_backend, :srv, quot;250 OKnquot;]
   [:resp, quot;250 OKnquot;]




                                                         SMTP + SPAM Filtering
                                                               building a state-machine



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
@PostRank: Beanstalkd + Ruby Proxy
                                                              because RAM is still expensive




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy         @igrigorik #railsconf
~ 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!




                                                                  Beanstalkd Math



Ruby Proxies + EventMachine       http://bit.ly/railsconf-proxy    @igrigorik #railsconf
Observations:
         1. Each job is rescheduled several times
         2. > 95% are scheduled for > 3 hours into the future


                              Memory is wasted…


          3. Beanstalkd does not have overflow page-to-disk


                     We’ll add it ourselves!
                                                                      Extending Beanstalkd



Ruby Proxies + EventMachine           http://bit.ly/railsconf-proxy        @igrigorik #railsconf
1 “Medium” EC2 Instance
                       Intercepting Proxy



                                                                         MySQL
                                         EM-Proxy




                                                                        Beanstalkd




                                  @PostRank: “Chronos Scheduler”


Ruby Proxies + EventMachine          http://bit.ly/railsconf-proxy      @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 11300) do |conn|
  conn.server :srv, :host => quot;127.0.0.1quot;, :port => 11301
  PUT_CMD = /put (d+) (d+) (d+) (d+)rn/

  conn.on_data do |data|
   if put = data.match(PUT_CMD)                                  Intercept PUT command
     if put[2].to_i > 600
       p [:put, :archive]
       # INSERT INTO ....
       conn.send_data quot;INSERTED 9999rnquot;
       data = nil
     end
    end

   data
  end

  conn.on_response do |backend, resp|
   resp
  end
 end




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy   @igrigorik #railsconf
Proxy.start(:host => quot;0.0.0.0quot;, :port => 11300) do |conn|
  conn.server :srv, :host => quot;127.0.0.1quot;, :port => 11301
  PUT_CMD = /put (d+) (d+) (d+) (d+)rn/

  conn.on_data do |data|
   if put = data.match(PUT_CMD)

      if put[2].to_i > 600                                    If over 10 minutes…
        p [:put, :archive]
        # INSERT INTO ....

      conn.send_data quot;INSERTED 9999rnquot;
      data = nil
     end
    end                                                        Archive & Reply

   data
  end

  conn.on_response do |backend, resp|
   resp
  end
 end



Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
Overload the protocol



                                                                       MySQL
                                    EM-Proxy


                                                                PUT




                                           RESERVE, PUT, …
        put job, 900
                                                                      Beanstalkd




                              @PostRank: “Chronos Scheduler”


Ruby Proxies + EventMachine     http://bit.ly/railsconf-proxy         @igrigorik #railsconf
400% cheaper + extensible!                  ~79,000,000 jobs, 4GB RAM



                                                                          MySQL
                                       EM-Proxy


                                                                   PUT



     Upcoming jobs: ~ 1M
                                              RESERVE, PUT, …
                                                                         Beanstalkd




                              @PostRank: “Chronos Scheduler”


Ruby Proxies + EventMachine        http://bit.ly/railsconf-proxy         @igrigorik #railsconf
%w[ Transparent <Intercepting> Caching … +
                                                              solution for every problem




Ruby Proxies + EventMachine   http://bit.ly/railsconf-proxy     @igrigorik #railsconf
Slides: http://bit.ly/railsconf-proxy
    Code: http://github.com/igrigorik/em-proxy

    Twitter: @igrigorik




                                                             Thanks. Questions?

                              The slides…                         Twitter                           My blog


Ruby Proxies + EventMachine       http://bit.ly/railsconf-proxy             @igrigorik #railsconf

More Related Content

What's hot

Communication in Python and the C10k problem
Communication in Python and the C10k problemCommunication in Python and the C10k problem
Communication in Python and the C10k problemJose Galarza
 
Building WebSocket and Server Side Events Applications using Atmosphere
Building WebSocket and Server Side Events Applications using AtmosphereBuilding WebSocket and Server Side Events Applications using Atmosphere
Building WebSocket and Server Side Events Applications using Atmospherejfarcand
 
Ruby 1.9 Fibers
Ruby 1.9 FibersRuby 1.9 Fibers
Ruby 1.9 FibersKevin Ball
 
Ruby vs Node ShiningRay Shanghai
Ruby vs Node ShiningRay ShanghaiRuby vs Node ShiningRay Shanghai
Ruby vs Node ShiningRay ShanghaiJackson Tian
 
No Callbacks, No Threads - RailsConf 2010
No Callbacks, No Threads - RailsConf 2010No Callbacks, No Threads - RailsConf 2010
No Callbacks, No Threads - RailsConf 2010Ilya Grigorik
 
Scaling Ruby with Evented I/O - Ruby underground
Scaling Ruby with Evented I/O - Ruby undergroundScaling Ruby with Evented I/O - Ruby underground
Scaling Ruby with Evented I/O - Ruby undergroundOmer Gazit
 
Writing Portable WebSockets in Java
Writing Portable WebSockets in JavaWriting Portable WebSockets in Java
Writing Portable WebSockets in Javajfarcand
 
Solving some of the scalability problems at booking.com
Solving some of the scalability problems at booking.comSolving some of the scalability problems at booking.com
Solving some of the scalability problems at booking.comIvan Kruglov
 
Why async matters
Why async mattersWhy async matters
Why async matterstimbc
 
Smart Gamma - Real-Time Web applications with PHP and Websocket.
Smart Gamma - Real-Time Web applications with PHP and Websocket.Smart Gamma - Real-Time Web applications with PHP and Websocket.
Smart Gamma - Real-Time Web applications with PHP and Websocket.Evgeniy Kuzmin
 
20141210 rakuten techtalk
20141210 rakuten techtalk20141210 rakuten techtalk
20141210 rakuten techtalkHiroshi SHIBATA
 
Gearman - Job Queue
Gearman - Job QueueGearman - Job Queue
Gearman - Job QueueDiego Lewin
 
WebSockets wiith Scala and Play! Framework
WebSockets wiith Scala and Play! FrameworkWebSockets wiith Scala and Play! Framework
WebSockets wiith Scala and Play! FrameworkFabio Tiriticco
 
The details of CI/CD environment for Ruby
The details of CI/CD environment for RubyThe details of CI/CD environment for Ruby
The details of CI/CD environment for RubyHiroshi SHIBATA
 
So you think JSON is cool?
So you think JSON is cool?So you think JSON is cool?
So you think JSON is cool?Herval Freire
 
Faster PHP apps using Queues and Workers
Faster PHP apps using Queues and WorkersFaster PHP apps using Queues and Workers
Faster PHP apps using Queues and WorkersRichard Baker
 

What's hot (19)

Communication in Python and the C10k problem
Communication in Python and the C10k problemCommunication in Python and the C10k problem
Communication in Python and the C10k problem
 
Concurrency in ruby
Concurrency in rubyConcurrency in ruby
Concurrency in ruby
 
Building WebSocket and Server Side Events Applications using Atmosphere
Building WebSocket and Server Side Events Applications using AtmosphereBuilding WebSocket and Server Side Events Applications using Atmosphere
Building WebSocket and Server Side Events Applications using Atmosphere
 
Ruby 1.9 Fibers
Ruby 1.9 FibersRuby 1.9 Fibers
Ruby 1.9 Fibers
 
Ruby vs Node ShiningRay Shanghai
Ruby vs Node ShiningRay ShanghaiRuby vs Node ShiningRay Shanghai
Ruby vs Node ShiningRay Shanghai
 
No Callbacks, No Threads - RailsConf 2010
No Callbacks, No Threads - RailsConf 2010No Callbacks, No Threads - RailsConf 2010
No Callbacks, No Threads - RailsConf 2010
 
Scaling Ruby with Evented I/O - Ruby underground
Scaling Ruby with Evented I/O - Ruby undergroundScaling Ruby with Evented I/O - Ruby underground
Scaling Ruby with Evented I/O - Ruby underground
 
Grape golilath
Grape golilathGrape golilath
Grape golilath
 
Writing Portable WebSockets in Java
Writing Portable WebSockets in JavaWriting Portable WebSockets in Java
Writing Portable WebSockets in Java
 
Speedy TDD with Rails
Speedy TDD with RailsSpeedy TDD with Rails
Speedy TDD with Rails
 
Solving some of the scalability problems at booking.com
Solving some of the scalability problems at booking.comSolving some of the scalability problems at booking.com
Solving some of the scalability problems at booking.com
 
Why async matters
Why async mattersWhy async matters
Why async matters
 
Smart Gamma - Real-Time Web applications with PHP and Websocket.
Smart Gamma - Real-Time Web applications with PHP and Websocket.Smart Gamma - Real-Time Web applications with PHP and Websocket.
Smart Gamma - Real-Time Web applications with PHP and Websocket.
 
20141210 rakuten techtalk
20141210 rakuten techtalk20141210 rakuten techtalk
20141210 rakuten techtalk
 
Gearman - Job Queue
Gearman - Job QueueGearman - Job Queue
Gearman - Job Queue
 
WebSockets wiith Scala and Play! Framework
WebSockets wiith Scala and Play! FrameworkWebSockets wiith Scala and Play! Framework
WebSockets wiith Scala and Play! Framework
 
The details of CI/CD environment for Ruby
The details of CI/CD environment for RubyThe details of CI/CD environment for Ruby
The details of CI/CD environment for Ruby
 
So you think JSON is cool?
So you think JSON is cool?So you think JSON is cool?
So you think JSON is cool?
 
Faster PHP apps using Queues and Workers
Faster PHP apps using Queues and WorkersFaster PHP apps using Queues and Workers
Faster PHP apps using Queues and Workers
 

Similar to Ruby Proxies for Scale Performance and Monitoring

When Two Worlds Collide: Java and Ruby in the Enterprise
When Two Worlds Collide: Java and Ruby in the EnterpriseWhen Two Worlds Collide: Java and Ruby in the Enterprise
When Two Worlds Collide: Java and Ruby in the Enterprisebenbrowning
 
[2011-17-C-4] Heroku & database.com
[2011-17-C-4] Heroku & database.com[2011-17-C-4] Heroku & database.com
[2011-17-C-4] Heroku & database.comMitch Okamoto
 
State of Developer Tools (WDS09)
State of Developer Tools (WDS09)State of Developer Tools (WDS09)
State of Developer Tools (WDS09)bgalbs
 
Plack basics for Perl websites - YAPC::EU 2011
Plack basics for Perl websites - YAPC::EU 2011Plack basics for Perl websites - YAPC::EU 2011
Plack basics for Perl websites - YAPC::EU 2011leo lapworth
 
Foreman - Process manager for applications with multiple components
Foreman - Process manager for applications with multiple componentsForeman - Process manager for applications with multiple components
Foreman - Process manager for applications with multiple componentsStoyan Zhekov
 
Everyday tools and tricks for scaling Node.js
Everyday tools and tricks for scaling Node.jsEveryday tools and tricks for scaling Node.js
Everyday tools and tricks for scaling Node.jsNikolay Stoitsev
 
Toster - Understanding the Rails Web Model and Scalability Options
Toster - Understanding the Rails Web Model and Scalability OptionsToster - Understanding the Rails Web Model and Scalability Options
Toster - Understanding the Rails Web Model and Scalability OptionsFabio Akita
 
Understanding the Rails web model and scalability options
Understanding the Rails web model and scalability optionsUnderstanding the Rails web model and scalability options
Understanding the Rails web model and scalability options.toster
 
Wakanda: NoSQL & SSJS for Model-driven Web Applications - SourceDevCon 2012
Wakanda: NoSQL & SSJS for Model-driven Web Applications - SourceDevCon 2012Wakanda: NoSQL & SSJS for Model-driven Web Applications - SourceDevCon 2012
Wakanda: NoSQL & SSJS for Model-driven Web Applications - SourceDevCon 2012Alexandre Morgaut
 
ECS19 - Damir Dobric - Designing and Operating modern applications with Micro...
ECS19 - Damir Dobric - Designing and Operating modern applications with Micro...ECS19 - Damir Dobric - Designing and Operating modern applications with Micro...
ECS19 - Damir Dobric - Designing and Operating modern applications with Micro...European Collaboration Summit
 
JRuby At LinkedIn
JRuby At LinkedInJRuby At LinkedIn
JRuby At LinkedInbaqhaidri
 

Similar to Ruby Proxies for Scale Performance and Monitoring (20)

When Two Worlds Collide: Java and Ruby in the Enterprise
When Two Worlds Collide: Java and Ruby in the EnterpriseWhen Two Worlds Collide: Java and Ruby in the Enterprise
When Two Worlds Collide: Java and Ruby in the Enterprise
 
Cucumber
CucumberCucumber
Cucumber
 
[2011-17-C-4] Heroku & database.com
[2011-17-C-4] Heroku & database.com[2011-17-C-4] Heroku & database.com
[2011-17-C-4] Heroku & database.com
 
State of Developer Tools (WDS09)
State of Developer Tools (WDS09)State of Developer Tools (WDS09)
State of Developer Tools (WDS09)
 
Ruby On Rails
Ruby On RailsRuby On Rails
Ruby On Rails
 
Where is my scalable API?
Where is my scalable API?Where is my scalable API?
Where is my scalable API?
 
Plack basics for Perl websites - YAPC::EU 2011
Plack basics for Perl websites - YAPC::EU 2011Plack basics for Perl websites - YAPC::EU 2011
Plack basics for Perl websites - YAPC::EU 2011
 
Foreman - Process manager for applications with multiple components
Foreman - Process manager for applications with multiple componentsForeman - Process manager for applications with multiple components
Foreman - Process manager for applications with multiple components
 
RubyConf Brazil 2011
RubyConf Brazil 2011RubyConf Brazil 2011
RubyConf Brazil 2011
 
Project Zero Php Quebec
Project Zero Php QuebecProject Zero Php Quebec
Project Zero Php Quebec
 
Web application intro
Web application introWeb application intro
Web application intro
 
COMET in Plone
COMET in PloneCOMET in Plone
COMET in Plone
 
Everyday tools and tricks for scaling Node.js
Everyday tools and tricks for scaling Node.jsEveryday tools and tricks for scaling Node.js
Everyday tools and tricks for scaling Node.js
 
Toster - Understanding the Rails Web Model and Scalability Options
Toster - Understanding the Rails Web Model and Scalability OptionsToster - Understanding the Rails Web Model and Scalability Options
Toster - Understanding the Rails Web Model and Scalability Options
 
Understanding the Rails web model and scalability options
Understanding the Rails web model and scalability optionsUnderstanding the Rails web model and scalability options
Understanding the Rails web model and scalability options
 
Project Zero JavaOne 2008
Project Zero JavaOne 2008Project Zero JavaOne 2008
Project Zero JavaOne 2008
 
Wakanda: NoSQL & SSJS for Model-driven Web Applications - SourceDevCon 2012
Wakanda: NoSQL & SSJS for Model-driven Web Applications - SourceDevCon 2012Wakanda: NoSQL & SSJS for Model-driven Web Applications - SourceDevCon 2012
Wakanda: NoSQL & SSJS for Model-driven Web Applications - SourceDevCon 2012
 
ECS19 - Damir Dobric - Designing and Operating modern applications with Micro...
ECS19 - Damir Dobric - Designing and Operating modern applications with Micro...ECS19 - Damir Dobric - Designing and Operating modern applications with Micro...
ECS19 - Damir Dobric - Designing and Operating modern applications with Micro...
 
Guides To Analyzing WebKit Performance
Guides To Analyzing WebKit PerformanceGuides To Analyzing WebKit Performance
Guides To Analyzing WebKit Performance
 
JRuby At LinkedIn
JRuby At LinkedInJRuby At LinkedIn
JRuby At LinkedIn
 

More from Ilya Grigorik

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

More from Ilya Grigorik (9)

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
 
Taming The RSS Beast
Taming The  RSS  BeastTaming The  RSS  Beast
Taming The RSS Beast
 

Recently uploaded

Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 

Recently uploaded (20)

Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 

Ruby Proxies for Scale Performance and Monitoring

  • 1. Ruby Proxies for Scale, Performance and Monitoring Ilya Grigorik @igrigorik Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 2. postrank.com/topic/ruby The slides… Twitter My blog Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 3. Code + Examples EventMachine Misc Proxies Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 4. Proxy Love Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 5. “Rails, Django, Seaside, Grails…” cant scale. Myth: Slow Frameworks Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 6. The Proxy Solution Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 7. The “More” Proxy Solution Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 8. Transparent Scalability Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 9. Load Balancer Reverse Proxy App Server MySQL Proxy Proxy as Middleware middleware ftw! Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 10. 90% use case %w*Transparent Intercepting Caching …+ There are many different types! Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 11. Transparent HAProxy App server A App server B Transparent, Cut-Through Proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 12. Transparent Proxy = Scalability Power Tool Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 13. Proxy Proxy App server A App server B App server C Problem: Staging Environment Production Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 14. Simulating traffic? Proxy Duplication App server C “Representative Load / Staging” Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 15. github.com/igrigorik/autoperf Replay log data, rinse, repeat Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 16. Profile of queries has changed Fail Load on production has changed Fail Parallel environment Fail Slower release cycle Fail Staging fail. Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 17. Duplex Ruby Proxy, FTW! Production Real (production) traffic Benchmark Benchmarking Proxy flash of the obvious Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 18. github.com/igrigorik/em-proxy Proxy DSL FTW! Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 19. EventMachine: Speed + Convenience building high performance network apps in Ruby Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 20. p quot;Startingquot; while true do EM.run do timers p quot;Running in EM reactorquot; network_io end other_io end puts quot;Almost donequot; EventMachine Reactor concurrency without threads Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 21. p quot;Startingquot; while true do EM.run do timers p quot;Running in EM reactorquot; network_io end other_io end puts quot;Almost donequot; EventMachine Reactor concurrency without threads Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 22. C++ core Easy concurrency without threading EventMachine Reactor concurrency without threads Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 23. 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 Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 24. 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 Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 25. EM.run do EM.add_timer(1) { p quot;1 second laterquot; } EM.add_periodic_timer(5) { p quot;every 5 secondsquot;} EM.defer { long_running_task() } end class Server < EM::Connection def receive_data(data) send_data(quot;Pong; #{data}quot;) end def unbind p [:connection_completed] end end EM.run do EM.start_server quot;0.0.0.0quot;, 3000, Server end Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 26. EM.run do EM.add_timer(1) { p quot;1 second laterquot; } EM.add_periodic_timer(5) { p quot;every 5 secondsquot;} EM.defer { long_running_task() } end class Server < EM::Connection def receive_data(data) send_data(quot;Pong; #{data}quot;) Connection Handler end def unbind p [:connection_completed] end end EM.run do Start Reactor EM.start_server quot;0.0.0.0quot;, 3000, Server end Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 27. http://bit.ly/aiderss-eventmachine by Dan Sinclair (Twitter: @dj2sincl) Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 28. Proxies for Monitoring, Performance and Scale welcome to the wonderful world of… Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 29. Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn| conn.server :name, :host => quot;127.0.0.1quot;, :port => 81 conn.on_data do |data| # ... end Relay Server conn.on_response do |server, resp| # ... end conn.on_finish do # ... end end EM-Proxy www.github.com/igrigorik/em-proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 30. Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn| conn.server :name, :host => quot;127.0.0.1quot;, :port => 81 conn.on_data do |data| # ... end Process incoming data conn.on_response do |server, resp| # ... end conn.on_finish do # ... end end EM-Proxy www.github.com/igrigorik/em-proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 31. Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn| conn.server :name, :host => quot;127.0.0.1quot;, :port => 81 conn.on_data do |data| # ... end Process response data conn.on_response do |server, resp| # ... end conn.on_finish do # ... end end EM-Proxy www.github.com/igrigorik/em-proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 32. Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn| conn.server :name, :host => quot;127.0.0.1quot;, :port => 81 conn.on_data do |data| # ... end conn.on_response do |server, resp| # ... end Post-processing step conn.on_finish do # ... end end EM-Proxy www.github.com/igrigorik/em-proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 33. %w[ <Transparent> Intercepting Caching … + solution for every problem Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 34. Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn| conn.server :srv, :host => quot;127.0.0.1quot;, :port => 81 # modify / process request stream conn.on_data do |data| p [:on_data, data] data end No data modifications # modify / process response stream conn.on_response do |server, resp| p [:on_response, server, resp] resp end end Port-Forwarding transparent proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 35. Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn| conn.server :srv, :host => quot;127.0.0.1quot;, :port => 81 conn.on_data do |data| data end conn.on_response do |backend, resp| Alter response resp.gsub(/hello/, 'good bye') end end Port-Forwarding + Alter transparent proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 36. %w[ Transparent <Intercepting> Caching … + solution for every problem Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 37. Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn| @start = Time.now @data = Hash.new(quot;quot;) Prod + Test conn.server :prod, :host => quot;127.0.0.1quot;, :port => 81 conn.server :test, :host => quot;127.0.0.1quot;, :port => 82 conn.on_data do |data| data.gsub(/User-Agent: .*?rn/, 'User-Agent: em-proxyrn') end conn.on_response do |server, resp| @data[server] += resp resp if server == :prod end conn.on_finish do p [:on_finish, Time.now - @start] p @data end end Duplex HTTP: Benchmarking Intercepting proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 38. Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn| @start = Time.now @data = Hash.new(quot;quot;) conn.server :prod, :host => quot;127.0.0.1quot;, :port => 81 conn.server :test, :host => quot;127.0.0.1quot;, :port => 82 conn.on_data do |data| data.gsub(/User-Agent: .*?rn/, 'User-Agent: em-proxyrn') end conn.on_response do |server, resp| Respond from production @data[server] += resp resp if server == :prod end conn.on_finish do p [:on_finish, Time.now - @start] p @data end end Duplex HTTP: Benchmarking Intercepting proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 39. Proxy.start(:host => quot;0.0.0.0quot;, :port => 80) do |conn| @start = Time.now @data = Hash.new(quot;quot;) conn.server :prod, :host => quot;127.0.0.1quot;, :port => 81 conn.server :test, :host => quot;127.0.0.1quot;, :port => 82 conn.on_data do |data| data.gsub(/User-Agent: .*?rn/, 'User-Agent: em-proxyrn') end conn.on_response do |server, resp| @data[server] += resp resp if server == :prod end Run post-processing conn.on_finish do p [:on_finish, Time.now - @start] p @data end end Duplex HTTP: Benchmarking Intercepting proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 40. [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=>quot;HTTP/1.1 200 OKrnConnection: closernDate: Fri, 01 May 2009 04:20:00 GMTrnContent-Type: text/plainrnrnhello world: 0quot;, :test=>quot;HTTP/1.1 200 OKrnConnection: closernDate: Fri, 01 May 2009 04:20:00 GMTrnContent-Type: text/plainrnrnhello world: 1quot;} Duplex HTTP: Benchmarking Intercepting proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 41. [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=>quot;HTTP/1.1 200 OKrnConnection: closernDate: Fri, 01 May 2009 04:20:00 GMTrnContent-Type: text/plainrnrnhello world: 0quot;, :test=>quot;HTTP/1.1 200 OKrnConnection: closernDate: Fri, 01 May 2009 04:20:00 GMTrnContent-Type: text/plainrnrnhello world: 1quot;} Duplex HTTP: Benchmarking Intercepting proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 42. Same response, different turnaround time Different response body! Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 43. Woops! Validating Proxy easy, real-time diagnostics Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 44. Hacking SMTP for fun and profit Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 45. Proxy.start(:host => quot;0.0.0.0quot;, :port => 2524) do |conn| conn.server :srv, :host => quot;127.0.0.1quot;, :port => 2525 # RCPT TO:<name@address.com>rn RCPT_CMD = /RCPT TO:<(.*)?>rn/ Intercept Addressee conn.on_data do |data| if rcpt = data.match(RCPT_CMD) if rcpt[1] != quot;ilya@igvita.comquot; conn.send_data quot;550 No such user herenquot; data = nil end end data end conn.on_response do |backend, resp| resp end Defeating SMTP Wildcards end Intercepting proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 46. Proxy.start(:host => quot;0.0.0.0quot;, :port => 2524) do |conn| conn.server :srv, :host => quot;127.0.0.1quot;, :port => 2525 # RCPT TO:<name@address.com>rn RCPT_CMD = /RCPT TO:<(.*)?>rn/ conn.on_data do |data| Allow: ilya@igvita.com if rcpt = data.match(RCPT_CMD) if rcpt[1] != quot;ilya@igvita.comquot; conn.send_data quot;550 No such user herenquot; data = nil 550 Error otherwise end end data end conn.on_response do |backend, resp| resp end Defeating SMTP Wildcards end Intercepting proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 47. [ilya@igvita] > mailtrap run –p 2525 –f /tmp/mailtrap.log [ilya@igvita] > ruby examples/smtp_whitelist.rb > require 'net/smtp‘ > smtp = Net::SMTP.start(quot;localhostquot;, 2524) > smtp.send_message quot;Hello World!quot;, quot;ilya@aiderss.comquot;, quot;ilya@igvita.comquot; => #<Net::SMTP::Response:0xb7dcff5c @status=quot;250quot;, @string=quot;250 OKnquot;> > smtp.finish => #<Net::SMTP::Response:0xb7dcc8d4 @status=quot;221quot;, @string=quot;221 Seeyanquot;> > smtp.send_message quot;Hello World!quot;, quot;ilya@aiderss.comquot;, “missing_user@igvita.comquot; => Net::SMTPFatalError: 550 No such user here Duplex HTTP: Benchmarking Intercepting proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 48. [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(quot;localhostquot;, 2524) > smtp.send_message quot;Hello World!quot;, quot;ilya@aiderss.comquot;, quot;ilya@igvita.comquot; => #<Net::SMTP::Response:0xb7dcff5c @status=quot;250quot;, @string=quot;250 OKnquot;> > smtp.finish => #<Net::SMTP::Response:0xb7dcc8d4 @status=quot;221quot;, @string=quot;221 Seeyanquot;> > smtp.send_message quot;Hello World!quot;, quot;ilya@aiderss.comquot;, “missing_user@igvita.comquot; => Net::SMTPFatalError: 550 No such user here Denied! Duplex HTTP: Benchmarking Intercepting proxy Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 49. “Hacking SMTP”.gsub(/Hacking/, ’Kung-fu’) DIY spam filtering with Defensio Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 50. Proxy.start(:host => quot;0.0.0.0quot;, :port => 2524) do |conn| conn.server :srv, :host => quot;127.0.0.1quot;, :port => 2525 RCPT_CMD = /RCPT TO:<(.*)?>rn/ FROM_CMD = /MAIL FROM:<(.*)?>rn/ MSG_CMD = /354 Start your message/ MSGEND_CMD = /^.rn/ Intercept commands conn.on_data do |data| #… end conn.on_response do |server, resp| p [:resp, resp] if resp.match(MSG_CMD) @buffer = true @msg = quot;quot; end resp SMTP + SPAM Filtering end end building a state-machine Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 51. Proxy.start(:host => quot;0.0.0.0quot;, :port => 2524) do |conn| conn.server :srv, :host => quot;127.0.0.1quot;, :port => 2525 RCPT_CMD = /RCPT TO:<(.*)?>rn/ FROM_CMD = /MAIL FROM:<(.*)?>rn/ MSG_CMD = /354 Start your message/ MSGEND_CMD = /^.rn/ conn.on_data do |data| #… end conn.on_response do |server, resp| p [:resp, resp] if resp.match(MSG_CMD) Flag & Buffer message @buffer = true @msg = quot;quot; end resp SMTP + SPAM Filtering end end building a state-machine Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 52. Save data conn.on_data do |data| @from = data.match(FROM_CMD)[1] if data.match(FROM_CMD) @rcpt = data.match(RCPT_CMD)[1] if data.match(RCPT_CMD) @done = true if data.match(MSGEND_CMD) if @buffer @msg += data Buffer data = nil end if @done #… end data SMTP + SPAM Filtering end building a state-machine Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 53. conn.on_data do |data| @from = data.match(FROM_CMD)[1] if data.match(FROM_CMD) @rcpt = data.match(RCPT_CMD)[1] if data.match(RCPT_CMD) @done = true if data.match(MSGEND_CMD) if @buffer @msg += data Flag end of message data = nil end if @done #… Process message end data SMTP + SPAM Filtering end building a state-machine Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 54. Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 55. @buffer = false uri = URI.parse('http://api.defensio.com/app/1.2/audit/key.yaml') res = Net::HTTP.post_form(uri, { quot;owner-urlquot; => quot;http://www.github.com/igrigorik/em-proxyquot;, quot;user-ipquot; => quot;216.16.254.254quot;, quot;article-datequot; => quot;2009/05/01quot;, quot;comment-authorquot; => @from, Defensio API quot;comment-typequot; => quot;commentquot;, quot;comment-contentquot; => @msg}) defensio = YAML.load(res.body)['defensio-result'] p [:defensio, quot;SPAM: #{defensio['spam']}quot;] if defensio['spam'] conn.send_data quot;550 No such user herenquot; else data = @msg end SMTP + SPAM Filtering building a state-machine Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 56. @buffer = false uri = URI.parse('http://api.defensio.com/app/1.2/audit/key.yaml') res = Net::HTTP.post_form(uri, { quot;owner-urlquot; => quot;http://www.github.com/igrigorik/em-proxyquot;, quot;user-ipquot; => quot;216.16.254.254quot;, quot;article-datequot; => quot;2009/05/01quot;, quot;comment-authorquot; => @from, quot;comment-typequot; => quot;commentquot;, quot;comment-contentquot; => @msg}) defensio = YAML.load(res.body)['defensio-result'] p [:defensio, quot;SPAM: #{defensio['spam']}quot;] if defensio['spam'] Pass / Deny Message conn.send_data quot;550 No such user herenquot; else data = @msg end SMTP + SPAM Filtering building a state-machine Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 57. Protocol Trace [:relay_from_backend, :srv, quot;354 Start your messagequot;] [:resp, quot;354 Start your messagequot;] [:srv, quot;nquot;] [:relay_from_backend, :srv, quot;nquot;] [:resp, quot;nquot;] [:connection, quot;Hello Worldrnquot;] [:connection, quot;.rnquot;] [:defensio, quot;SPAM: false, Spaminess: 0.4quot;] [:srv, quot;250 OKnquot;] [:relay_from_backend, :srv, quot;250 OKnquot;] [:resp, quot;250 OKnquot;] SMTP + SPAM Filtering building a state-machine Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 58. @PostRank: Beanstalkd + Ruby Proxy because RAM is still expensive Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 59. ~ 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! Beanstalkd Math Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 60. Observations: 1. Each job is rescheduled several times 2. > 95% are scheduled for > 3 hours into the future Memory is wasted… 3. Beanstalkd does not have overflow page-to-disk We’ll add it ourselves! Extending Beanstalkd Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 61. 1 “Medium” EC2 Instance Intercepting Proxy MySQL EM-Proxy Beanstalkd @PostRank: “Chronos Scheduler” Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 62. Proxy.start(:host => quot;0.0.0.0quot;, :port => 11300) do |conn| conn.server :srv, :host => quot;127.0.0.1quot;, :port => 11301 PUT_CMD = /put (d+) (d+) (d+) (d+)rn/ conn.on_data do |data| if put = data.match(PUT_CMD) Intercept PUT command if put[2].to_i > 600 p [:put, :archive] # INSERT INTO .... conn.send_data quot;INSERTED 9999rnquot; data = nil end end data end conn.on_response do |backend, resp| resp end end Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 63. Proxy.start(:host => quot;0.0.0.0quot;, :port => 11300) do |conn| conn.server :srv, :host => quot;127.0.0.1quot;, :port => 11301 PUT_CMD = /put (d+) (d+) (d+) (d+)rn/ conn.on_data do |data| if put = data.match(PUT_CMD) if put[2].to_i > 600 If over 10 minutes… p [:put, :archive] # INSERT INTO .... conn.send_data quot;INSERTED 9999rnquot; data = nil end end Archive & Reply data end conn.on_response do |backend, resp| resp end end Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 64. Overload the protocol MySQL EM-Proxy PUT RESERVE, PUT, … put job, 900 Beanstalkd @PostRank: “Chronos Scheduler” Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 65. 400% cheaper + extensible! ~79,000,000 jobs, 4GB RAM MySQL EM-Proxy PUT Upcoming jobs: ~ 1M RESERVE, PUT, … Beanstalkd @PostRank: “Chronos Scheduler” Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 66. %w[ Transparent <Intercepting> Caching … + solution for every problem Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf
  • 67. Slides: http://bit.ly/railsconf-proxy Code: http://github.com/igrigorik/em-proxy Twitter: @igrigorik Thanks. Questions? The slides… Twitter My blog Ruby Proxies + EventMachine http://bit.ly/railsconf-proxy @igrigorik #railsconf