¿Cuántos procesos debo especificar en un WSGIDaemonProcess mientras ejecuto Django a través de mod_wsgi?

23

Digamos que tengo 2 sitios (Superusuario y Serverfault) ejecutándose desde su propio host virtual Apache en una caja. Los 2 sitios funcionan con Django y se ejecutan en Apache con mod-wsgi. Un archivo de configuración típico para uno de los sitios tendrá el siguiente aspecto:

WSGIDaemonProcess serverfault.com user=www-data group=www-data processes=5

El host es una máquina Linux con 4 GB de RAM que ejecuta Ubuntu. ¿Alguien puede sugerir la cantidad de procesos que debería especificar arriba para mis 2 sitios? Supongamos que tienen el mismo tráfico que los sitios reales de Superusuario y Serverfault.

Thierry Lam
fuente

Respuestas:

22

Bueno, ¿cuánto tráfico tienen los sitios reales de Superusuario y Serverfault? Las hipótesis no son muy útiles si no tienen suficiente información para facilitar la respuesta ...

El recuento del proceso en el peor de los casos debe ser el número máximo de solicitudes por segundo que desea que el sitio pueda manejar, dividido por el número de solicitudes por segundo que un proceso puede manejar si todas esas solicitudes se realizan en su acción más lenta (por lo tanto el recíproco del tiempo de procesamiento de esa acción). Agregue el factor fudge que considere apropiado, en función del intervalo de confianza de sus mediciones de tiempo y requisitos.

El recuento promedio de casos es el mismo, pero divide el requerimiento / segundo por la media ponderada de sus solicitudes por segundo para cada acción (el peso es el porcentaje de solicitudes que espera alcanzar esa acción en particular). Nuevamente, los factores fudge son útiles.

El límite superior real de cuántos procesos puede ejecutar en la máquina está dictado por la cantidad superior de memoria que toma cada proceso; ponga en cola un proceso, luego ejecute una variedad de acciones que consumen mucha memoria (aquellas que recuperan y procesan una gran cantidad de datos, por lo general) en contra de él con un conjunto de datos realista (si solo usa un conjunto de datos de juguete para las pruebas, digamos 50 o 100 filas, entonces, si una de sus acciones recupera y manipula cada fila de la tabla, no será una buena medida para cuando esa tabla crezca a 10,000 filas) para ver a qué se eleva el uso de la memoria. Puede restringir artificialmente el uso de memoria por proceso con un script que cosecha trabajadores que alcanzan un cierto umbral de uso de memoria, con el riesgo de causar problemas desagradables si establece ese umbral demasiado bajo.

Una vez que tenga la cifra de uso de memoria, deduzca cierta cantidad de memoria para la sobrecarga del sistema (me gusta 512 MB), deduzca un montón más si tiene otros procesos ejecutándose en la misma máquina (como una base de datos), y luego un poco más para asegurarse de que no se quede sin espacio en la memoria caché del disco (depende del tamaño del conjunto de trabajo de su disco, pero nuevamente iría con no menos de 512 MB). Esa es la cantidad de memoria que divide por el uso de memoria por proceso para llegar al límite.

Si la cantidad de procesos que necesita para atender su carga máxima es mayor que la cantidad de procesos que puede ajustar en la caja, necesitará más máquinas (o mover la base de datos a otra máquina, en el caso más simple).

Ahí tienes, varios años de experiencia escalando sitios web destilados en una pequeña y simple publicación SF.

womble
fuente
Otro factor importante para la cantidad de procesos / subprocesos es el tiempo que pueden tomar las solicitudes individuales para ser manejado y la distribución general en todos los períodos de tiempo posibles. En otras palabras, cuántas solicitudes en un momento dado deben manejarse, lo que lleva un tiempo de respuesta mayor que el promedio. Por lo tanto, no es tan simple como solo solicitudes teóricas / segundo, ya que el impacto de esas solicitudes más largas puede ser significativo y dictar indebidamente los parámetros de configuración generales. FWIW mod_wsgi 3.0 incluirá una colección de estadísticas incorporada para tratar de capturar datos sobre esto para ayudar a la configuración.
Graham Dumpleton el
@Graham: relee mi respuesta, cubrí eso con cierto detalle. Las solicitudes / segundo son solo el recíproco del tiempo de respuesta, y es más fácil dividir por un número entero requerido / segundo que multiplicarlo por un decimal.
womble
Sin embargo, no puede enfocarse solo en la peor respuesta del caso, ni solo en el promedio. Es necesario ponderarlo de acuerdo con el porcentaje de solicitudes que caen en períodos de tiempo, es decir, la distribución en todos los tiempos posibles. Si realmente tomara su peor tiempo de respuesta del caso, se le ocurrirían requisitos poco realistas. El problema es que es muy difícil saber qué fórmula usar. Es por eso que en mod_wsgi 3.0 habrá una recopilación de estadísticas incorporadas que analiza la utilización de subprocesos y para qué porcentaje por conteo y tiempo que cualquier número de subprocesos está en uso en cualquier momento.
Graham Dumpleton el
3
Tal vez el problema sea que solo está viendo procesos donde me preocupa cómo los subprocesos que usa cada proceso tienen en cuenta y eso no es tan simple. En otras palabras, esa directiva WSGIDaemonProcess indica 5 procesos donde cada proceso está por defecto usando 15 hilos. Por mucho que leí en su descripción, está asumiendo procesos de un solo subproceso. Si no es así, indíqueme cómo su modelo atiende hilos y problemas de contención / escalado en todo el GIL. Por lo tanto, califique que su descripción solo es válida para procesos de subproceso único y no discutiré.
Graham Dumpleton el
2
¿No es el enfoque "multiproceso-Apache + multiproceso-wsgi" la mejor apuesta hasta que esté 99% seguro de que su código Python y todas las dependencias son seguras para subprocesos?
Tomasz Zieliński
9

La respuesta de womble es asombrosa, aunque un poco difícil de entender y aplicar para los inexpertos. Me gustaría dar algunos números empíricos y una comparación de aplicaciones de "contenido simple" versus "comercio electrónico".

No hay mucho material para establecer diferentes casos de uso en relación con su configuración apropiada de mod_wsgi, así que espero que esté bien usar un poco de prosa aquí.

A) Sitios y micrositios de CMS

Ejecutamos varios sitios web de clientes, la mayoría de ellos principalmente sitios de contenido o micro sitios que alojan django CMS, algunos formularios personalizados y, a veces, Celery para tareas en segundo plano programadas. Estos sitios no tienen hambre de recursos, varios de ellos funcionan felizmente en paralelo en un solo Intel Xeon de 4 núcleos con 32 GB de RAM. Aquí está la configuración que utilizamos para cada uno de este tipo de sitios:

WSGIDaemonProcess example.com user=www-data processes=2 maximum-requests=100

Estoy hablando de aproximadamente 40 sitios en un solo servidor, la mayoría de ellos con su sitio de ensayo funcionando en modo de espera. Con 2 procesos (que tienen 15 subprocesos cada uno, por defecto) los sitios están bien, aunque limitados en su capacidad de asignar recursos del servidor. Por qué esta configuración es suficiente puede justificarse con la naturaleza simple de la aplicación (CMS): nunca se espera que una solicitud tarde más de un par de milisegundos en completarse. Apache siempre se mantendrá relajado, y también lo será la carga de la CPU.

B) Sitios de comercio electrónico

Los sitios más complejos que realizamos se caracterizan por operaciones locales computacionalmente económicas pero dependencias externas (por ejemplo, servicios web que proporcionan datos de reserva) que son costosas en términos de tiempo de transacción. Las operaciones con solicitudes externas ocupan subprocesos durante mucho más tiempo, por lo que necesita más subprocesos para atender al mismo número de usuarios (en comparación con un sitio simple de CMS desde arriba). Peor aún, los subprocesos se bloquean ocasionalmente cuando un servicio externo no puede responder una solicitud de inmediato, a veces durante un par de segundos. Esto puede conducir al desagradable efecto secundario de que los subprocesos que colocan solicitudes en la misma cola de servicio se agoten, hasta que todos los subprocesos mod_wsgi disponibles se agoten y se bloqueen la espera.

Para esos escenarios, hemos tratado de usar 6procesos sin ver mucha diferencia, y terminamos 12viendo un impulso incomparable en el rendimiento y la estabilidad operativa:

WSGIDaemonProcess example.com user=www-data processes=12 maximum-requests=100

El sitio maneja fácilmente algunas pruebas de carga simples con 150 y 250 usuarios paralelos, manteniéndose bien receptivo (mientras que con los 2procesos el sitio es inutilizable para atender a 50 usuarios en paralelo). El 2 CPU 6 Core Intel Xeon con 32 GB de RAM funciona muy por debajo del 25% de uso de la CPU bajo esa carga, el uso de RAM casi se mantiene constante en menos del 25% también. Tenga en cuenta que aquí utilizamos una máquina dedicada solo para un solo sitio, por lo que no robaremos recursos que otros sitios puedan necesitar.

Conclusión

El uso de un mayor número de procesos es una compensación entre permitir que Apache haga uso de los recursos del sistema disponibles o no. Si desea mantener un sistema de servidor estable (¡no un sitio web!) En condiciones de "ataque", mantenga el número bajo. Si desea que Apache lo ayude a usar los recursos del sistema (CPU, RAM) cuando sea necesario, elija un número más alto. Qué tan alto puede llegar se calcula de manera similar a lo que se describe en la respuesta aceptada anteriormente, y en última instancia está limitado por la potencia de CPU y RAM disponibles.

(PD: mantengo la sección ConfigurationDirectives del wiki del proyecto modwsgi debajo de mi almohada para una lectura de fondo similar a Apache. También asegúrese de comprender y monitorear las conexiones abiertas de su servidor Apache ).

Peterino
fuente
Gran publicación, pero ¿por qué no configuras el número de hilos? Dado que GIL de Python niega muchas de las ventajas de los hilos, supongo que desearía tener más procesos que hilos, pero ¿hay alguna ventaja en especificar el recuento de hilos?
Cerin
El número predeterminado de threads15 es según la documentación . No creo que haya una ventaja para especificar eso explícitamente. De hecho, recuerdo haberlo dejado fuera por una razón: había alguna publicación en SO o parte de alguna documentación que recomendaba omitir el valor para evitar efectos secundarios (lo sé, eso suena extraño). Desafortunadamente, no encuentro esa fuente ahora. Para el resto de su pregunta (GIL), probablemente sea más experto que yo, lo siento.
Peterino
Gracias por esta configuración empírica. Sin embargo, tenga en cuenta que de acuerdo con este post You should never use maximum-requests in a production system unless you understand the implications and have a specific temporary need.
raratiru