Estoy jugando con la concurrencia en Ruby (1.9.3-p0), y he creado una tarea proxy de E/S muy simple y muy simple. Primero, probé el enfoque sin bloqueo:concurrencia de Ruby: E/S no bloqueantes frente a subprocesos
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, pensé que debía estar haciendo algo mal. ¿Un tiempo de solicitud promedio de 5.6s para una tarea en la que estamos principalmente esperando E/S? Probé con otro:
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 poco mejor, pero no es lo que yo llamaría un éxito. Finalmente, probé una implementación enhebrada:
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
Eso fue realmente, realmente sorprendente. ¿Me estoy perdiendo de algo? ¿Por qué EM está funcionando tan mal aquí? ¿Hay algún ajuste que deba hacer? Intenté varias combinaciones (unicornio, varias configuraciones de arcoiris, etc.), pero ninguna de ellas se acercó siquiera al enhebrado simple y antiguo de bloqueo de E/S.
Ideas, comentarios y, obviamente, sugerencias para mejores implementaciones son bienvenidas.
No debe utilizar servidores distantes para las pruebas, la latencia puede variar. Deberías intentar de nuevo la prueba asíncrona con menos fibras, con 20 fibras obtengo 300ms/solicitud versus 1s/solicitud con 1000 fibras usando tu línea ab exacta. Su servidor de subprocesos está utilizando el grupo de subprocesos de matriz de eventos predeterminado, que tiene 20 subprocesos de forma predeterminada. – Schmurfy
No estoy seguro, establecer el tamaño de la agrupación de fibra en 20 realmente disminuye el rendimiento en mi caja. – BSM
Tal vez no 20 pero 1000 es muy alto, lo probé con un servidor local, por lo que el tiempo de respuesta fue muy bajo. – Schmurfy