Pregunta

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, fecths algunos datos y actualiza un objeto de registro activo.

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

¿Alguna idea? Gracias.

¿Fue útil?

Solución

Algunos pensamientos ...

  • El hecho de que necesite leer 50 sitios y, naturalmente, que desee un poco de trabajo paralelo, no significa que necesita 50 procesos o subprocesos. Necesita equilibrar la desaceleración y los gastos generales. ¿Qué tal si tenemos 10 o 20 procesos, cada uno lee algunos sitios?

  • Dependiendo de qué Ruby estés usando, ten cuidado con los hilos verdes, es posible que no obtengas el resultado paralelo que deseas

  • Es posible que desee estructurarlo como a la inversa, inetd del lado del cliente, y usar connect_nonblock y IO.select para obtener las conexiones paralelas que desea Haciendo que todos los servidores respondan en paralelo. Realmente no necesita un procesamiento paralelo de los resultados, solo necesita conectarse a todos los servidores en paralelo, porque ahí es donde realmente se encuentra la latencia.

Entonces, algo como esto de la biblioteca de sockets ... extiéndalo 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

Otros consejos

En realidad, es posible ejecutar varios trabajadores delayed_job.

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

Entonces, en teoría, simplemente puedes ejecutar:

$ RAILS_ENV=production script/delayed_job -n 50 start

Esto generará 50 procesos, sin embargo, no estoy seguro de si eso se recomendaría dependiendo de los recursos del sistema en el que se esté ejecutando.


Una opción alternativa sería utilizar hilos . Simplemente genera un nuevo hilo para cada uno de tus trabajos.

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

ActiveRecord::Base.allow_concurrency = true

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

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

La segunda forma es crear un solo trabajo que use Curl :: Multi para ejecutar sus 50 solicitudes TCP simultáneas. Puede encontrar más información sobre esto aquí: http://curl-multi.rubyforge.org/ De esa manera, podría tener un procesador en segundo plano ejecutando todas sus solicitudes de TCP en paralelo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top