2012-02-12 12 views
12

Sto giocando con la concorrenza in Ruby (1.9.3-p0) e ho creato un'attività proxy proxy I/O molto semplice. Per prima cosa ho provato l'approccio non bloccante:Concorrenza di Ruby: I/O non bloccante vs thread

require 'rack' 
require 'rack/fiber_pool' 
require 'em-http' 
require 'em-synchrony' 
require 'em-synchrony/em-http' 

proxy = lambda {|*| 
    result = EM::Synchrony.sync EventMachine::HttpRequest.new('http://google.com').get 
    [200, {}, [result.response]] 
} 

use Rack::FiberPool, :size => 1000 
run proxy 

=begin 
$ thin -p 3000 -e production -R rack-synchrony.ru start 
>> Thin web server (v1.3.1 codename Triple Espresso) 

$ ab -c100 -n100 http://localhost:3000/ 
Concurrency Level:  100 
Time taken for tests: 5.602 seconds 
HTML transferred:  21900 bytes 
Requests per second: 17.85 [#/sec] (mean) 
Time per request:  5602.174 [ms] (mean) 
=end 

Hmm, ho pensato che dovevo fare qualcosa di sbagliato. Un tempo medio di richiesta di 5,6 secondi per un'attività in cui ci aspettiamo principalmente I/O? Ne ho provato un altro:

require 'sinatra' 
require 'sinatra/synchrony' 
require 'em-synchrony/em-http' 

get '/' do 
    EM::HttpRequest.new("http://google.com").get.response 
end 

=begin 
$ ruby sinatra-synchrony.rb -p 3000 -e production 
== Sinatra/1.3.1 has taken the stage on 3000 for production with backup from Thin 
>> Thin web server (v1.3.1 codename Triple Espresso) 

$ ab -c100 -n100 http://localhost:3000/ 
Concurrency Level:  100 
Time taken for tests: 5.476 seconds 
HTML transferred:  21900 bytes 
Requests per second: 18.26 [#/sec] (mean) 
Time per request:  5475.756 [ms] (mean) 
=end 

Hmm, un po 'meglio, ma non quello che definirei un successo. Infine, ho provato un'implementazione con thread:

require 'rack' 
require 'excon' 

proxy = lambda {|*| 
    result = Excon.get('http://google.com') 
    [200, {}, [result.body]] 
}  
run proxy 

=begin 
$ thin -p 3000 -e production -R rack-threaded.ru --threaded --no-epoll start 
>> Thin web server (v1.3.1 codename Triple Espresso) 

$ ab -c100 -n100 http://localhost:3000/ 
Concurrency Level:  100 
Time taken for tests: 2.014 seconds 
HTML transferred:  21900 bytes 
Requests per second: 49.65 [#/sec] (mean) 
Time per request:  2014.005 [ms] (mean) 
=end 

Questo è stato davvero, davvero sorprendente. Mi sto perdendo qualcosa qui? Perché l'EM si sta comportando così male qui? C'è qualche messa a punto che devo fare? Ho provato varie combinazioni (unicorno, diverse configurazioni di arcobaleni, ecc.), Ma nessuna di esse si avvicinava nemmeno al semplice, vecchio threading di I/O-blocking.

Idee, commenti e - ovviamente - suggerimenti per migliori implementazioni sono i benvenuti.

+1

Non si dovrebbe utilizzare un server remoto per i test, la latenza può variare. Dovresti riprovare il test asincrono con meno fibre, con 20 fibre ottengo 300ms/request contro 1s/request con 1000 fibre usando la tua esatta linea ab. Il server threadato utilizza il pool di thread di eventmachine predefinito, che è 20 thread per impostazione predefinita. – Schmurfy

+0

Non sono sicuro, l'impostazione della dimensione del pool di fibre su 20 diminuisce effettivamente le prestazioni sul mio box. – BSM

+0

Forse non 20 ma 1000 è veramente alto, ho provato con un server locale quindi il tempo di risposta era veramente basso. – Schmurfy

risposta

2

Vedi come il tuo "Tempo per richiesta" è esattamente uguale al "Tempo impiegato per i test"? Questo è un artefatto di segnalazione a causa del fatto che il numero di richieste (-n) è uguale al livello di concorrenza (-c). Il tempo medio è la simultaneità simultanea/num-richieste. Quindi la media riportata quando -n == -c sarà il tempo della richiesta più lunga. Dovresti condurre le tue ab con -n> -c da diversi fattori per ottenere misure ragionevoli.

Sembra che si stia utilizzando una versione precedente di ab poiché una versione relativamente recente riporta risultati molto più dettagliati per impostazione predefinita. Eseguendo direttamente contro google, mostro un tempo medio simile == quando tempo -n == -c, e ottengo numeri più ragionevoli quando -n> -c. Volete davvero vedere il req/sec, la media tra tutte le richieste simultanee e la ripartizione del livello di servizio finale per ottenere una migliore comprensione.

$ ab -c50 -n50 http://google.com/ 
This is ApacheBench, Version 2.3 <$Revision: 655654 $> 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
Licensed to The Apache Software Foundation, http://www.apache.org/ 

Benchmarking google.com (be patient).....done 


Server Software:  gws 
Server Hostname:  google.com 
Server Port:   80 

Document Path:  /
Document Length:  219 bytes 

Concurrency Level:  50 
Time taken for tests: 0.023 seconds   <<== note same as below 
Complete requests:  50 
Failed requests:  0 
Write errors:   0 
Non-2xx responses:  50 
Total transferred:  27000 bytes 
HTML transferred:  10950 bytes 
Requests per second: 2220.05 [#/sec] (mean) 
Time per request:  22.522 [ms] (mean)  <<== note same as above 
Time per request:  0.450 [ms] (mean, across all concurrent requests) 
Transfer rate:   1170.73 [Kbytes/sec] received 

Connection Times (ms) 
       min mean[+/-sd] median max 
Connect:  1 2 0.6  3  3 
Processing:  8 9 2.1  9  19 
Waiting:  8 9 2.1  9  19 
Total:   11 12 2.1  11  22 
WARNING: The median and mean for the initial connection time are not within a normal deviation 
     These results are probably not that reliable. 

Percentage of the requests served within a certain time (ms) 
    50%  11 
    66%  12 
    75%  12 
    80%  12 
    90%  12 
    95%  12 
    98%  22 
    99%  22 
100%  22 (longest request)  <<== note same as total and mean above 


$ ab -c50 -n500 http://google.com/ 
This is ApacheBench, Version 2.3 <$Revision: 655654 $> 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
Licensed to The Apache Software Foundation, http://www.apache.org/ 

Benchmarking google.com (be patient) 
Completed 100 requests 
Completed 200 requests 
Completed 300 requests 
Completed 400 requests 
Completed 500 requests 
Finished 500 requests 


Server Software:  gws 
Server Hostname:  google.com 
Server Port:   80 

Document Path:  /
Document Length:  219 bytes 

Concurrency Level:  50 
Time taken for tests: 0.110 seconds 
Complete requests:  500 
Failed requests:  0 
Write errors:   0 
Non-2xx responses:  500 
Total transferred:  270000 bytes 
HTML transferred:  109500 bytes 
Requests per second: 4554.31 [#/sec] (mean) 
Time per request:  10.979 [ms] (mean) 
Time per request:  0.220 [ms] (mean, across all concurrent requests) 
Transfer rate:   2401.69 [Kbytes/sec] received 

Connection Times (ms) 
       min mean[+/-sd] median max 
Connect:  1 1 0.7  1  3 
Processing:  8 9 0.7  9  13 
Waiting:  8 9 0.7  9  13 
Total:   9 10 1.3  10  16 

Percentage of the requests served within a certain time (ms) 
    50%  10 
    66%  11 
    75%  11 
    80%  12 
    90%  12 
    95%  13 
    98%  14 
    99%  15 
100%  16 (longest request)