NGINX lidera el grupo en cuanto a rendimiento web, y todo se debe a la forma en que está diseñado el software. Mientras que muchos servidores web y servidores de aplicação utilizan una arquitectura simple basada en procesos o subprocesos, NGINX se destaca con una sofisticada arquitectura impulsada por eventos que le permite escalar a cientos de miles de conexiones simultáneas en hardware moderno.
La infografía Inside NGINX profundiza en la arquitectura de procesos de alto nivel para ilustrar cómo NGINX maneja múltiples conexiones dentro de un solo proceso. Este blog explica cómo funciona todo con más detalle.
Para comprender mejor este diseño, es necesario comprender cómo funciona NGINX. NGINX tiene un proceso maestro (que realiza operaciones privilegiadas como leer la configuración y vincularse a los puertos) y una serie de procesos de trabajo y auxiliares.
# servicio nginx restart * Reiniciando nginx # ps -ef --forest | grep nginx root 32475 1 0 13:36 ? 00:00:00 nginx: proceso maestro /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 32476 32475 0 13:36 ? 00:00:00 _ nginx: proceso de trabajo nginx 32477 32475 0 13:36 ? 00:00:00 _ nginx: proceso de trabajo nginx 32479 32475 0 13:36 ? 00:00:00 _ nginx: proceso de trabajo nginx 32480 32475 0 13:36 ? 00:00:00 _ nginx: proceso de trabajo nginx 32481 32475 0 13:36 ? 00:00:00 _ nginx: proceso del administrador de caché nginx 32482 32475 0 13:36 ? 00:00:00 _ nginx: proceso de carga de caché
En este servidor de cuatro núcleos, el proceso maestro NGINX crea cuatro procesos de trabajo y un par de procesos auxiliares de caché que administran el caché de contenido en disco.
La base fundamental de cualquier aplicação Unix es el hilo o proceso. (Desde la perspectiva del sistema operativo Linux, los subprocesos y los procesos son prácticamente idénticos; la principal diferencia es el grado en que comparten memoria). Un hilo o proceso es un conjunto autónomo de instrucciones que el sistema operativo puede programar para ejecutarse en un núcleo de CPU. La mayoría de las aplicações complejas ejecutan múltiples subprocesos o procesos en paralelo por dos razones:
Los procesos y los subprocesos consumen recursos. Cada uno utiliza memoria y otros recursos del sistema operativo, y es necesario intercambiarlos dentro y fuera de los núcleos (una operación llamada cambio de contexto ). La mayoría de los servidores modernos pueden manejar cientos de pequeños subprocesos o procesos activos simultáneamente, pero el rendimiento se degrada seriamente una vez que se agota la memoria o cuando una alta carga de E/S provoca un gran volumen de cambios de contexto.
La forma común de diseñar aplicações de red es asignar un hilo o proceso a cada conexión. Esta arquitectura es simple y fácil de implementar, pero no escala cuando la aplicação necesita manejar miles de conexiones simultáneas.
NGINX utiliza un modelo de proceso predecible que se adapta a los recursos de hardware disponibles:
La configuración de NGINX recomendada en la mayoría de los casos (ejecutar un proceso de trabajo por núcleo de CPU) permite el uso más eficiente de los recursos de hardware. Lo configuras estableciendo el parámetro auto
en la directivaworker_processes
:
procesos_de_trabajo automáticos;
Cuando un servidor NGINX está activo, solo los procesos de trabajo están ocupados. Cada proceso de trabajo maneja múltiples conexiones de manera no bloqueante, lo que reduce la cantidad de cambios de contexto.
Cada proceso de trabajo es de un solo subproceso y se ejecuta de forma independiente, capturando nuevas conexiones y procesándolas. Los procesos pueden comunicarse utilizando memoria compartida para datos de caché compartidos, datos de persistencia de sesión y otros recursos compartidos.
Cada proceso de trabajo de NGINX se inicializa con la configuración de NGINX y el proceso maestro le proporciona un conjunto de sockets de escucha.
Los procesos de trabajo de NGINX comienzan esperando eventos en los sockets de escucha ( accept_mutex y fragmentación del socket del kernel ). Los eventos se inician mediante nuevas conexiones entrantes. Estas conexiones se asignan a una máquina de estados : la máquina de estados HTTP es la más comúnmente utilizada, pero NGINX también implementa máquinas de estados para el tráfico de flujo (TCP sin procesar) y para varios protocolos de correo (SMTP, IMAP y POP3).
La máquina de estados es esencialmente el conjunto de instrucciones que le indican a NGINX cómo procesar una solicitud. La mayoría de los servidores web que realizan las mismas funciones que NGINX utilizan una máquina de estados similar; la diferencia radica en la implementación.
Piense en la máquina de estados como si fuera las reglas del ajedrez. Cada transacción HTTP es un juego de ajedrez. En un lado del tablero de ajedrez está el servidor web: un gran maestro que puede tomar decisiones muy rápidamente. En el otro lado está el cliente remoto: el navegador web que accede al sitio o a la aplicação a través de una red relativamente lenta.
Sin embargo, las reglas del juego pueden ser muy complicadas. Por ejemplo, es posible que el servidor web necesite comunicarse con otras partes (mediante un proxy a una aplicação ascendente) o hablar con un servidor de autenticación. Los módulos de terceros en el servidor web pueden incluso ampliar las reglas del juego.
Recuerde nuestra descripción de un proceso o hilo como un conjunto autónomo de instrucciones que el sistema operativo puede programar para ejecutarse en un núcleo de CPU. La mayoría de los servidores y aplicações web utilizan un modelo de proceso por conexión o de hilo por conexión para jugar al ajedrez. Cada proceso o hilo contiene las instrucciones para jugar un juego hasta el final. Durante el tiempo que el servidor ejecuta el proceso, éste pasa la mayor parte del tiempo "bloqueado", esperando a que el cliente complete su siguiente movimiento.
El punto importante a recordar es que cada conexión HTTP activa (cada partida de ajedrez) requiere un proceso o hilo dedicado (un gran maestro). Esta arquitectura es simple y fácil de ampliar con módulos de terceros ('nuevas reglas'). Sin embargo, hay un enorme desequilibrio: la conexión HTTP, bastante liviana, representada por un descriptor de archivo y una pequeña cantidad de memoria, se asigna a un hilo o proceso separado, un objeto de sistema operativo muy pesado. Es una comodidad de programación, pero implica un enorme desperdicio.
¿Quizás hayas oído hablar de las partidas de exhibición simultáneas , en las que un gran maestro de ajedrez juega contra docenas de oponentes al mismo tiempo?
Así es como un proceso de trabajo NGINX juega al “ajedrez”. Cada trabajador (recuerde: generalmente hay un trabajador por cada núcleo de CPU) es un gran maestro que puede jugar cientos (de hecho, cientos de miles) de juegos simultáneamente.
Un trabajador nunca bloquea el tráfico de la red, esperando que su “oponente” (el cliente) responda. Una vez realizado su movimiento, el trabajador procede inmediatamente a otros juegos en los que hay movimientos pendientes de ser procesados, o da la bienvenida a nuevos jugadores en la puerta.
NGINX se escala muy bien para soportar cientos de miles de conexiones por proceso de trabajo. Cada nueva conexión crea otro descriptor de archivo y consume una pequeña cantidad de memoria adicional en el proceso de trabajo. Hay muy poca sobrecarga adicional por conexión. Los procesos NGINX pueden permanecer anclados a las CPU. Los cambios de contexto son relativamente poco frecuentes y ocurren cuando no hay trabajo que hacer.
En el enfoque de bloqueo, de conexión por proceso, cada conexión requiere una gran cantidad de recursos adicionales y sobrecarga, y los cambios de contexto (intercambio de un proceso a otro) son muy frecuentes.
Para obtener una explicación más detallada, consulte este artículo sobre la arquitectura NGINX, de Andrew Alexeev, vicepresidente de Desarrollo Corporativo y cofundador de NGINX, Inc.
Con un ajuste de sistema adecuado, NGINX puede escalar para manejar cientos de miles de conexiones HTTP simultáneas por proceso de trabajo y puede absorber picos de tráfico (una afluencia de juegos nuevos) sin perder el ritmo.
La arquitectura de procesos de NGINX, con una pequeña cantidad de procesos de trabajo, permite una actualización muy eficiente de la configuración e incluso del propio binario de NGINX.
Actualizar la configuración de NGINX es una operación muy simple, liviana y confiable. Por lo general, solo significa ejecutar el comando nginx
-s
reload
, que verifica la configuración en el disco y envía una señal SIGHUP al proceso maestro.
Cuando el proceso maestro recibe un SIGHUP, hace dos cosas:
Este proceso de recarga puede provocar un pequeño aumento en el uso de CPU y memoria, pero generalmente es imperceptible en comparación con la carga de recursos de las conexiones activas. Puede recargar la configuración varias veces por segundo (y muchos usuarios de NGINX hacen exactamente eso). Muy raramente, surgen problemas cuando hay muchas generaciones de procesos de trabajo NGINX esperando que se cierren las conexiones, pero incluso estos se resuelven rápidamente.
El proceso de actualización binaria de NGINX logra el Santo Grial de la alta disponibilidad: puede actualizar el software sobre la marcha, sin caídas de conexión, tiempos de inactividad o interrupciones del servicio.
El proceso de actualización binaria es similar en su enfoque a la recarga elegante de la configuración. Un nuevo proceso maestro NGINX se ejecuta en paralelo con el proceso maestro original y comparten los sockets de escucha. Ambos procesos están activos y sus respectivos procesos de trabajo manejan el tráfico. Luego puedes hacer una señal al viejo maestro y a sus trabajadores para que salgan con gracia.
El proceso completo se describe con más detalle en Controlar NGINX .
La infografía Inside NGINX proporciona una descripción general de alto nivel de cómo funciona NGINX, pero detrás de esta simple explicación hay más de diez años de innovación y optimización que permiten a NGINX ofrecer el mejor rendimiento posible en una amplia gama de hardware manteniendo la seguridad y confiabilidad que requieren las aplicações web modernas.
Si desea leer más sobre las optimizaciones en NGINX, consulte estos excelentes recursos:
SO_REUSEPORT
)"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.