2012-02-18 18 views
7

Al usar Unicorn en Heroku. El aumento de escala tendrá problemas, ya que se puede acceder al dyno web recién escalado mediante una solicitud cuando aún está cargando la aplicación. Lo que principalmente resulta en un error de tiempo de espera.¿Precargo correctamente la aplicación en Heroku + Unicornio?

Hice un poco de lectura en http://codelevy.com/2010/02/09/getting-started-with-unicorn.html y https://github.com/blog/517-unicorn

Los dos artículos sugirió el uso de preload_app true. Y un bloque after_fork y before_fork.

En Rails 3+, ¿aún se requiere el código en el before_block? Leí en alguna parte, de lo contrario. ¿Alguien que haya experimentado la configuración antes y quisiera compartir?

¿Me falta algo más? ¿Precargo la aplicación correctamente?

# config/initializers/unicorn.rb 
# Read from: 
# http://michaelvanrooijen.com/articles/2011/06/01-more-concurrency-on-a-single-heroku-dyno-with-the-new-celadon-cedar-stack/ 
worker_processes 3 # amount of unicorn workers to spin up 
timeout 30   # restarts workers that hang for 90 seconds 

# Noted from http://codelevy.com/2010/02/09/getting-started-with-unicorn.html 
# and https://github.com/blog/517-unicorn 
preload_app true 

after_fork do |server, worker| 
    ActiveRecord::Base.establish_connection 
end 

before_fork do |server, worker| 
    ## 
    # When sent a USR2, Unicorn will suffix its pidfile with .oldbin and 
    # immediately start loading up a new version of itself (loaded with a new 
    # version of our app). When this new Unicorn is completely loaded 
    # it will begin spawning workers. The first worker spawned will check to 
    # see if an .oldbin pidfile exists. If so, this means we've just booted up 
    # a new Unicorn and need to tell the old one that it can now die. To do so 
    # we send it a QUIT. 
    # 
    # Using this method we get 0 downtime deploys. 

    old_pid = Rails.root + '/tmp/pids/unicorn.pid.oldbin' 
    if File.exists?(old_pid) && server.pid != old_pid 
    begin 
     Process.kill("QUIT", File.read(old_pid).to_i) 
    rescue Errno::ENOENT, Errno::ESRCH 
     # someone else did our job for us 
    end 
    end 
end 

Respuesta

2

Lo que ves aquí es esperado. En el momento en que aumente la velocidad mediante un dinamómetro, la plataforma Heroku desplegará esa babosa en un nuevo dinamómetro, que está completamente aislado de los otros dinamómetros (es decir, otro maestro del unicornio).

Una vez que el dyno se implementa y se ejecuta (se inicia de manera efectiva), la malla de enrutamiento comenzará a enviar solicitudes a ese dyno, que es cuando Rails se iniciará en el Unicorn, o lo que sea, servidor que tenga configurado.

Sin embargo, una vez que llega la solicitud, tiene una ventana de 30 segundos para devolver sus datos o la solicitud será expirada en la malla de enrutamiento (error H12).

Por lo tanto, para resumir, su problema no tiene que ver con bifurcar, es que su aplicación no puede iniciarse en 30 segundos, de ahí los tiempos de espera anticipados. Preocuparse por los archivos PID y de bifurcación no es algo de lo que deba preocuparse en la plataforma Heroku.

+0

Hola Neil. La solución es precargar la aplicación para evitar que las solicitudes entren hasta que el dyno (maestro de unicornios) cargue la aplicación por completo. Mi preocupación aquí es si necesito el código en el bloque 'before_fork'. –

+0

Su before_fork no logrará nada. Como dije antes, el problema radica en el hecho de que la malla de enrutamiento de Heroku te enviará solicitudes antes de que tu Unicornio haya comenzado. Precargar la aplicación no resolverá esto. –

+0

Si ese es el caso. ¿Cómo se pueden evitar los errores de tiempo de espera al hacer girar/escalar nuevas dininas web en Heroku? –

1

Sólo una respuesta parcial pero fueron capaces de reducir estos tiempos de espera de escala desagradables con esta configuración unicornio:

worker_processes 3 # amount of unicorn workers to spin up 
timeout 30   # restarts workers that hang for 30 seconds 
preload_app true 

# hack: traps the TERM signal, preventing unicorn from receiving it and performing its quick shutdown. 
# My signal handler then sends QUIT signal back to itself to trigger the unicorn graceful shutdown 
# http://stackoverflow.com/a/9996949/235297 
before_fork do |_server, _worker| 
    Signal.trap 'TERM' do 
    puts 'intercepting TERM and sending myself QUIT instead' 
    Process.kill 'QUIT', Process.pid 
    end 
end 

# Fix PostgreSQL SSL error 
# http://stackoverflow.com/a/8513432/235297 
after_fork do |server, worker| 
    defined?(ActiveRecord::Base) and 
    ActiveRecord::Base.establish_connection 
end 

Además, utilizo heroku labs:enable preboot (ver https://devcenter.heroku.com/articles/labs-preboot/). Desafortunadamente, todavía veo algunos tiempos de espera cuando se aumenta la velocidad de los dineros web.

Aquí hay una discusión en el foro de soporte HireFire, inicié: http://hirefireapp.tenderapp.com/discussions/problems/205-scaling-up-and-down-too-quickly-provoking-503s

+0

Seguir el mismo enfoque y no ayuda. Parece que incluso con la precarga hay una demora entre cuando Unicorn comienza a "escuchar" y cuando los trabajadores bifurcados están "listos", para mí esto es> 30s por lo que incluso con todo * y * preboot obtengo errores H12. –

1

preload_app true ayudaron para nuestra aplicación, así que darle una oportunidad si estás viendo problemas con los tiempos de espera durante el despliegue/reinicio. Los comentarios que dicen que no ayudaron me hicieron pensar que no valía la pena intentarlo, y luego me di cuenta de que efectivamente era la solución que necesitábamos.

Nuestra situación era una aplicación Rails lenta de arrancar utilizando preboot. En algunos despliegues y reinicios, obtendríamos muchos tiempos de espera, hasta el punto de que el sitio fue considerado inactivo por nuestro monitoreo de tiempo de actividad.

Nos dimos cuenta de que con preload_app false, Unicorn enlazará su puerto primero y luego cargará la aplicación. Tan pronto como ata al puerto, Heroku comienza a enviar tráfico. Pero lleva bastante tiempo cargar esta aplicación lenta, de modo que el tráfico obtiene tiempos de espera.

Esto es fácil de verificar ejecutando Unicorn en dev, intentando acceder al sitio inmediatamente después de iniciar Unicorn, y comprobando si obtiene un error de tipo "no hay servidor en ese puerto" (deseable) o una solicitud muy lenta (no deseable).

Cuando en su lugar establezcamos preload_app true, tomará más tiempo hasta que Unicorn vincula el puerto, pero una vez que lo hace y Heroku lo envía, está listo para responder.

Cuestiones relacionadas