start run rails pumactl ruby-on-rails ruby multithreading unicorn puma

ruby on rails - run - ¿De qué se benefician más los procesos de múltiples procesos VS los servidores de múltiples subprocesos?



run puma ruby (2)

Puma es en realidad multiproceso y multiproceso. Puede invocarlo en "modo agrupado" donde generará múltiples trabajadores bifurcados que se ejecutarán en diferentes núcleos en MRI. Dado que Puma es multiproceso, probablemente sea apropiado para ejecutar una cantidad de procesos igual al número de núcleos en el servidor. Entonces, para un servidor de 4 núcleos, algo como esto sería apropiado:

puma -t 8:32 -w 4 --preload

Esto manejará hasta 32 subprocesos simultáneos, con hasta 4 subprocesos ejecutándose en las CPU al mismo tiempo y debería poder maximizar los recursos de la CPU en el servidor. El argumento --preload precarga la aplicación y aprovecha las mejoras de ruby ​​2.0 COW en la recolección de basura para reducir el uso de RAM.

Si su aplicación pasa un tiempo considerable esperando otros servicios (servicios de búsqueda, bases de datos, etc.), esto supondrá una gran mejora. Cuando un hilo se bloquea, otro hilo en el mismo proceso puede agarrar la CPU y funcionar. Puede admitir hasta 32 solicitudes en paralelo en este ejemplo, mientras que solo toma el golpe de ejecutar 4 procesos en la RAM.

Con Unicornio, tendría que desembolsar a 32 trabajadores, lo que tomaría el golpe de ejecutar 32 procesos en RAM, lo que es un gran desperdicio.

Si todo lo que su aplicación hace es un problema de CPU, esto será altamente ineficiente, y usted debería reducir la cantidad de unicornios, y los beneficios de Puma sobre Unicornio se reducirían. Pero en el caso de Unicorn, tienes que evaluar tu aplicación y determinar el número correcto. Puma tenderá a optimizarse generando más subprocesos, y su rendimiento debería ir desde no peor que Unicorn (en el caso de la CPU pura) hasta ser mucho mejor que Unicorn (en el caso de una aplicación que duerme mucho).

Por supuesto, si usa Rubinius o JRuby, entonces no es un concurso, y puede generar un proceso que se ejecute en varios núcleos y maneje los 32 subprocesos.

TL; DR es que no creo que haya muchas ventajas para Unicorn sobre Puma ya que Puma en realidad usa ambos modelos.

Por supuesto, no sé nada sobre la confiabilidad de Puma vs Unicorn en la ejecución del software de producción en el mundo real. Una cosa de la que debe preocuparse es que si hace garabatos sobre un estado global en un hilo, puede afectar a otras solicitudes que se ejecutan al mismo tiempo, lo que puede producir resultados indeterminados. Como Unicorn no usa hilos, no hay problemas de concurrencia. Espero que para este momento, tanto Puma como Rails estén maduros con respecto a los problemas de concurrencia y que Puma fuera utilizable en la producción. Sin embargo, no necesariamente esperaría que todos los complementos y rubygem de rieles que encontré en GitHub sean seguros para subprocesos, y esperaría tener que hacer algún trabajo adicional. Pero una vez que tenga el éxito suficiente para encontrar problemas de subprocesos en bibliotecas de terceros, probablemente sea lo suficientemente grande como para no poder pagar el costo de RAM de ejecutar tantos procesos Unicorn. OTOH, entiendo errores de concurrencia y estoy bien con Ruby, por lo que el costo de la depuración puede ser mucho menor para mí que el costo de comprar RAM en la nube. YMMV.

También tenga en cuenta que no estoy seguro de si debe contar los núcleos hiperhilos o los núcleos físicos al estimar el valor para pasar a ''-w'' y debería realizar una prueba de perfección, junto con una prueba de perf para qué valores usar para -t. Aunque incluso si ejecuta el doble de la cantidad de procesos que ''necesita'', el programador de procesos en el kernel debería poder manejarlo sin problemas hasta que sature la CPU, en cuyo caso tendrá problemas más grandes de todos modos. Probablemente recomendaría iniciar un proceso para cada núcleo de subproceso (en MRI).

¿Alguien puede explicar cuál es el cuello de botella de cada método de concurrencia?

Servidores como Unicornio (basado en procesos) y Puma (basado en hilos).

¿Cada método prefiere núcleos de CPU? ¿trapos? o simplemente la velocidad del reloj? ¿O una combinación especial?

¿Cómo determinar las características de CPU óptimas necesarias en caso de usar servidores dedicados?

¿Y cómo determinar la mejor cantidad de trabajadores en el caso de Unicorn o la cantidad de hilos en el caso de Puma?


Unicorn está basado en el proceso, lo que significa que cada instancia de ruby ​​tendrá que existir en su propio proceso . Eso puede estar en el área de 500 mb para cada proceso, lo que agotará rápidamente los recursos del sistema. Puma, al estar basado en subprocesos, no usará la misma cantidad de memoria para alcanzar, en teoría, la misma cantidad de concurrencia.

Unicornio , dado que se ejecutan múltiples procesos, tendrá un paralelismo entre los diferentes procesos. Esto está limitado por los núcleos de la CPU (más núcleos pueden ejecutar más procesos al mismo tiempo), pero el núcleo cambiará entre los procesos activos, por lo que se pueden ejecutar más de 4 u 8 procesos (sin embargo, muchos de los núcleos que tenga). Usted estará limitado por la memoria de su máquina. Hasta hace poco, ruby ​​no era compatible con la copia en escritura, lo que significaba que CADA proceso tenía su propia memoria heredada (unicornio es un servidor de preforking). Ruby 2.0 es fácil de copiar y escribir, lo que podría significar que unicornio no tendrá que cargar todos los procesos secundarios en la memoria. No estoy 100% claro en esto. Lea sobre copia en escritura, y eche un vistazo al impresionante libro de jessie storimer ''trabajando con procesos de Unix''. Estoy bastante seguro de que lo cubrió allí.

Puma es un servidor de hilos. MRI Ruby, debido al bloqueo global del intérprete (GIL), solo puede ejecutar una sola tarea vinculada a la CPU a la vez (consulte el episodio 127 de ruby ​​tapas, paralelo fib). El contexto cambiará entre los subprocesos, pero siempre que sea una tarea vinculada a la CPU (por ejemplo, el procesamiento de datos) solo ejecutará un único subproceso de ejecución. Esto se vuelve interesante si ejecuta su servidor con una implementación diferente de Ruby, como JRuby o Rubinius. No tienen el GIL y pueden procesar una gran cantidad de información en paralelo. JRuby es bastante rápido y, si bien Rubinius es lento en comparación con MRI, Rubinius de procesos múltiples es más rápido que MRI. Sin embargo, durante la IO sin bloqueo (por ejemplo, escribir en una base de datos, realizar una solicitud web), MRI contextualizará el cambio a un subproceso que no se está ejecutando y funcionará allí, y luego volverá al subproceso anterior cuando se haya devuelto la información.

Para Unicornio , diría que el cuello de botella es la memoria y la velocidad del reloj. Para Puma , diría que el cuello de botella es su elección de intérprete (MRI vs Rubinius o JRuby) y el tipo de trabajo que realiza su servidor (muchas tareas vinculadas a la CPU vs IO sin bloqueo).

Hay toneladas de grandes recursos en este debate. Echa un vistazo a los libros de Jessie Storimer sobre estos temas, trabajando con hilos de rubí y trabajando con procesos de Unix ; lea este breve resumen de los servidores de preformación de ryan tomayko y busque en Google para obtener más información.

No sé cuál es la mejor cantidad de trabajador para Unicorn o Puma en su caso. Lo mejor que puedes hacer es ejecutar pruebas de rendimiento y hacer lo que es correcto para ti . No hay una talla para todos. (aunque creo que el estándar del puma es usar un grupo de 16 hilos y bloquearlo)