ruby on rails - tutorial - Configuración de Puma Cluster en Heroku
puma config (2)
Necesito ayuda con mi configuración de Puma (Multi-Thread + Multi-Core Server) en mi aplicación RoR4 Heroku. Los documentos de Heroku sobre eso no están muy actualizados. Seguí esta: conexiones simultáneas y de base de datos para la configuración, que no menciona la configuración de un clúster, por lo que tuve que usar ambos tipos juntos (con hilos y multinúcleo).
Mi configuración actual:
./Procfile
web: bundle exec puma -p $PORT -C config/puma.rb
./config/puma.rb
environment production
threads 0,16
workers 4
preload_app!
on_worker_boot do
ActiveRecord::Base.connection_pool.disconnect!
ActiveSupport.on_load(:active_record) do
config = Rails.application.config.database_configuration[Rails.env]
config[''reaping_frequency''] = ENV[''DB_REAP_FREQ''] || 10 # seconds
config[''pool''] = ENV[''DB_POOL''] || 5
ActiveRecord::Base.establish_connection
end
end
Preguntas:
a) ¿Necesito la configuración before_fork / after_fork como en Unicorn, ya que los trabajadores del Cluster están bifurcados?
b) ¿Cómo afino el número de hilos según mi aplicación? ¿Cuál sería la razón para dejarlo caer? / ¿En qué casos haría una diferencia? ¿No está optimizado 0:16?
c) La base de datos Heroku permite 500 conexiones. ¿Cuál sería un buen valor para DB_POOL en función del subproceso, el trabajador y el conteo de dinamómetro? - ¿Cada subproceso por trabajador por dinamo requiere una única conexión de base de datos cuando se trabaja en paralelo?
En general: ¿Cómo debería ser mi configuración para la concurrencia y el rendimiento?
a) ¿Necesito la configuración before_fork / after_fork como en Unicorn, ya que los trabajadores del Cluster están bifurcados?
Normalmente no, pero ya que estás usando preload_app
, sí. La precarga de la aplicación hace que una instancia esté en funcionamiento y luego recorte el espacio de memoria para los trabajadores; el resultado es que sus inicializadores solo se ejecutan una vez (posiblemente asignando conexiones de base de datos y tal). En este caso, su código on_worker_boot
es apropiado. Si no está usando preload_app
, entonces cada trabajador se inicia solo, en cuyo caso el uso de un inicializador sería ideal para configurar la conexión personalizada como lo está haciendo. De hecho, sin preload_app
, su bloque on_worker_boot
se produciría un error porque en ese momento ActiveRecord y sus amigos ni siquiera están cargados.
b) ¿Cómo afino el número de hilos según mi aplicación? ¿Cuál sería la razón para dejarlo caer? / ¿En qué casos haría una diferencia? ¿No está optimizado 0:16?
En Heroku (y mis pruebas), es mejor hacer coincidir tus subprocesos min
/ max
, con un max
<= DB_POOL
. Los subprocesos mínimos permiten que su aplicación reduzca los recursos cuando no esté bajo carga, lo que normalmente es excelente para liberar recursos en el servidor, pero probablemente sea menos necesario en Heroku; que Dyno ya está dedicado a atender solicitudes web, también puede tenerlas listas y listas. Si bien no es necesario configurar sus subprocesos max
<= su variable de entorno DB_POOL
, corre el riesgo de consumir todas las conexiones de su base de datos en el grupo, entonces tiene un subproceso que desea una conexión pero no puede obtenerlo, y puede obtener el el antiguo "ActiveRecord :: ConnectionTimeoutError - no pudo obtener una conexión de base de datos en 5 segundos". error. Sin embargo, esto depende de su aplicación, muy bien podría tener max
> DB_POOL
y estar bien. Yo diría que su DB_POOL
debería ser al menos el mismo que el valor de sus subprocesos mínimos, aunque sus conexiones no estén cargadas con entusiasmo (los subprocesos 5: 5 no abrirán 5 conexiones si su aplicación nunca llega a la base de datos).
c) La base de datos Heroku permite 500 conexiones. ¿Cuál sería un buen valor para DB_POOL en función del subproceso, el trabajador y el conteo de dinamómetro? - ¿Cada subproceso por trabajador por dinamo requiere una única conexión de base de datos cuando se trabaja en paralelo?
El nivel de producción permite 500, para ser claro :)
Cada subproceso por trabajador por dinamómetro podría consumir una conexión, dependiendo de si todos intentan acceder a la base de datos al mismo tiempo. Por lo general, las conexiones se reutilizan una vez que se realizan, pero como mencioné en b)
, si sus hilos son mayores que su grupo, puede pasar un mal momento. Las conexiones se reutilizarán, todo esto es manejado por ActiveRecord, pero a veces no es lo ideal. A veces, las conexiones se vuelven inactivas, o mueren, y es por eso que se sugiere encender el Segador, para detectar y reclamar conexiones muertas.
No quieres menos conexiones de DB que hilos. Recuerde que cada proceso separado tiene su propio conjunto de conexiones, por lo que si su base de datos admite 20 conexiones y desea ejecutar 2 procesos, la mayoría de los subprocesos que puede ejecutar sin arriesgar los tiempos de espera son 10 subprocesos, cada uno con un conjunto de 10 conexiones.
Quieres dejar algunas conexiones para las sesiones de consola de Rails. También tenga en cuenta a los trabajadores de fondo, y si están roscados.
Si sus trabajadores están en un proceso separado (sidekiq), tendrán su propio grupo. Si los subprocesos de sus trabajadores se generan a partir del proceso web (girl_friday o sucker_punch), querrá que DB_POOL sea mayor que el número máximo de subprocesos web, ya que compartirán un grupo de conexiones.