2009-10-22 13 views
8

En mi aplicación Ruby on Rails necesito ejecutar 50 trabajos en segundo plano en paralelo. Cada trabajo crea una conexión TCP a un servidor diferente, recupera algunos datos y actualiza un objeto de registro activo.Ejecución de múltiples trabajos paralelos en segundo plano con Rails

Conozco diferentes soluciones para realizar esta tarea, pero cualquiera de ellas en paralelo. Por ejemplo, delayyed_job (DJ) podría ser una gran solución si solo pudiera ejecutar todos los trabajos en paralelo.

¿Alguna idea? Gracias.

+0

Otra solución aquí: http://stackoverflow.com/questions/16551466/parallelizing-methods-in-rails/16676981#16676981 – Subhas

+0

Interesante, gracias a que @RDX – fjyaniez

Respuesta

1

Algunos pensamientos ...

  • El hecho de que se necesita leer 50 sitios, y, naturalmente, quiere un trabajo en paralelo hace no media que necesita 50 procesos o hilos. Necesitas equilibrar la ralentización y la sobrecarga. ¿Qué hay de 10 o 20 procesos cada uno leer algunos sitios?

  • dependiendo de qué Rubí que está utilizando, tenga cuidado con los hilos verdes, que puede no obtener el resultado paralelo desea

  • Es posible que desee estructurarlo como un revés, inetd del lado del cliente, y use connect_nonblock y IO.select para obtener las conexiones paralelas que desee haciendo que todos los servidores respondan en paralelo. Realmente no necesita el procesamiento paralelo de los resultados, solo necesita alinearse en todos los servidores en paralelo, porque ahí es donde realmente está la latencia.

Por lo tanto, algo así desde la biblioteca de sockets ... ampliar para múltiples conexiones pendientes ...

require 'socket' 
include Socket::Constants 
socket = Socket.new(AF_INET, SOCK_STREAM, 0) 
sockaddr = Socket.sockaddr_in(80, 'www.google.com') 
begin 
    socket.connect_nonblock(sockaddr) 
    rescue Errno::EINPROGRESS 
    IO.select(nil, [socket]) 
    begin 
    socket.connect_nonblock(sockaddr) 
    rescue Errno::EISCONN 
    end 
end 
socket.write("GET/HTTP/1.0\r\n\r\n") 
# here perhaps insert IO.select. You may not need multiple threads OR multiple 
# processes with this technique, but if you do insert them here 
results = socket.read 
+0

IO.select podría ser útil en este caso, lo intentaré. Gracias. – fjyaniez

6

En realidad, es posible ejecutar varios trabajadores con retraso de trabajo.

De http://github.com/collectiveidea/delayed_job:

# Runs two workers in separate processes. 
$ RAILS_ENV=production script/delayed_job -n 2 start 
$ RAILS_ENV=production script/delayed_job stop 

Por lo tanto, en teoría, sólo podría ejecutar:

$ RAILS_ENV=production script/delayed_job -n 50 start 

Esto se generan 50 procesos, sin embargo no estoy seguro de si eso sería recomendable en función de los recursos del sistema en el que está ejecutando esto.


Una opción alternativa sería utilizar threads. Simplemente genere un nuevo hilo para cada uno de sus trabajos.

Una cosa para tener en cuenta es que este método es que ActiveRecord no es seguro para subprocesos. Puede que sea seguro para subprocesos utilizando la siguiente configuración:

ActiveRecord::Base.allow_concurrency = true 
+0

También puede ejecutar delayed_job trabajadores en varias máquinas. Dudo que obtengas muchos beneficios al ejecutar más trabajadores en una sola máquina que con núcleos de CPU, pero podrías repartir la carga ejecutándola en varias cajas. Si necesita ejecutar 50 simultáneamente, creo que va a necesitar distribuir el trabajo. –

+2

Voy a obtener beneficios al ejecutar varios trabajadores en una sola máquina porque la mayoría de los trabajadores serán bloqueados por IO – fjyaniez

0

Puesto que usted está trabajando con los carriles, aconsejaría que use delayed_job para hacer esto en lugar de dividirse en hilos o tenedores. La razón es que lidiar con tiempos de espera y cosas cuando el navegador está esperando puede ser un verdadero dolor. Hay dos enfoques que puede tomar con DJ

El primero es - generan más de 50 trabajadores. Dependiendo de su entorno, esta puede ser una solución bastante pesada para la memoria, pero funciona muy bien.Luego, cuando necesite ejecutar su trabajo, solo asegúrese de crear 50 trabajos únicos. Si hay demasiada acumulación de memoria y desea hacer las cosas de esta manera, cree un entorno separado que se desforre, específicamente para sus trabajadores.

La segunda forma es crear un único trabajo que utilice Curl :: Multi para ejecutar sus 50 solicitudes TCP simultáneas. Puede encontrar más información al respecto aquí: http://curl-multi.rubyforge.org/ De esta forma, podría tener un procesador de fondo que ejecutara todas sus solicitudes TCP en paralelo.

Cuestiones relacionadas