Ajuste de Rendimiento de Nginx: Optimizar Procesos de Trabajo y Conexiones
Ajusta los procesos de trabajo, conexiones de trabajo, límites de archivos, comportamiento keepalive y capacidad del upstream de Nginx sin adivinar.
Ajuste de Rendimiento de Nginx: Optimizar Procesos de Trabajo y Conexiones
El ajuste de rendimiento de Nginx a menudo comienza con dos configuraciones: procesos de trabajo y conexiones de trabajo. Estas configuraciones determinan cuántas solicitudes puede manejar tu servidor al mismo tiempo, por lo que pequeños errores pueden manifestarse como páginas lentas, descargas estancadas o errores de conexión durante picos de tráfico.
La buena noticia es que no necesitas adivinar al azar. Puedes ajustar Nginx haciendo coincidir su modelo de trabajo con tu CPU, límites de archivos, patrón de tráfico y comportamiento de la aplicación upstream.
Cómo Manejan el Tráfico los Trabajadores de Nginx
Nginx utiliza un proceso maestro y uno o más procesos de trabajo. El proceso maestro lee la configuración, inicia los trabajadores y maneja las recargas. Los trabajadores realizan el manejo real de las solicitudes.
Cada trabajador puede manejar muchas conexiones porque Nginx utiliza un modelo basado en eventos. Esto es diferente de los servidores web más antiguos que a menudo necesitaban un proceso o hilo por solicitud. Un trabajador de Nginx puede mantener miles de conexiones keepalive inactivas abiertas si el sistema operativo lo permite.
Las dos directivas principales generalmente se colocan en /etc/nginx/nginx.conf:
worker_processes auto;
events {
worker_connections 1024;
}
worker_processes auto; le dice a Nginx que cree un trabajador por cada núcleo de CPU disponible. Para la mayoría de los servidores Linux modernos, este es el punto de partida correcto. Evita codificar un valor que se vuelva incorrecto cuando cambies el tamaño de una máquina virtual.
worker_connections establece el número máximo de conexiones simultáneas que cada trabajador puede abrir. El límite superior aproximado es:
worker_processes * worker_connections
Si tienes 4 trabajadores y 4096 conexiones de trabajo, el máximo teórico es de 16,384 conexiones. En la vida real, el número utilizable es menor porque el tráfico de proxy inverso puede usar conexiones tanto del lado del cliente como del upstream.
Por ejemplo, si Nginx envía tráfico a una aplicación Node.js, una solicitud de usuario puede consumir una conexión de cliente más una conexión upstream. Eso significa que 16,384 conexiones abiertas podrían soportar cerca de 8,000 solicitudes proxy activas, dependiendo del keepalive y la sincronización de las solicitudes.
Elegir Valores de Procesos de Trabajo y Conexiones de Trabajo
Comienza con worker_processes auto a menos que tengas una razón específica para no hacerlo. Establecer manualmente este valor por encima del recuento de CPU rara vez ayuda. Puede aumentar el cambio de contexto y empeorar el rendimiento bajo carga.
Luego ajusta worker_connections según la concurrencia esperada. Una herramienta interna tranquila puede estar bien con 1024. Un sitio web público detrás de un balanceador de carga puede necesitar 4096, 8192 o más.
Una línea base práctica para muchos servidores de producción se ve así:
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
}
worker_rlimit_nofile aumenta el límite de descriptores de archivo disponible para los trabajadores de Nginx. Esto es importante porque cada socket de red utiliza un descriptor de archivo. Si el límite del sistema operativo se mantiene bajo, aumentar worker_connections por sí solo no ayudará.
También debes verificar el límite del administrador de servicios. En sistemas systemd, Nginx puede necesitar una anulación como:
[Service]
LimitNOFILE=65535
Después de cambiar los límites de systemd, recarga systemd y reinicia Nginx. Para obtener una referencia de comandos más amplia, consulta Comandos de control del servicio Nginx.
Ten cuidado con multi_accept on. Permite que un trabajador acepte tantas conexiones nuevas como sea posible después de recibir una notificación de disponibilidad. Esto puede ayudar durante ráfagas, pero no es mágico. Si tu aplicación upstream es lenta, aceptar conexiones más rápido puede llenar las colas más rápido.
Límites del Sistema Operativo que Afectan a Nginx
Las configuraciones de Nginx se basan en los límites de Linux. Si esos límites son demasiado pequeños, Nginx alcanzará un techo incluso cuando su propia configuración parezca generosa.
Verifica estas áreas al ajustar:
- Límite de archivos abiertos para el proceso de Nginx
- Configuraciones de backlog de red del kernel
- Disponibilidad de puertos efímeros para tráfico proxy pesado
- Comportamiento keepalive del upstream
- Valores de tiempo de espera de inactividad del balanceador de carga
El límite de archivos abiertos es el bloqueador más común. Si Nginx registra mensajes como worker_connections are not enough o too many open files, debes mirar tanto los límites de Nginx como los de systemd.
Las configuraciones de backlog son importantes cuando muchos clientes se conectan a la vez. Si la cola de aceptación del kernel se llena, los usuarios pueden ver tiempos de espera de conexión aunque el uso de la CPU parezca normal. Valores como net.core.somaxconn y net.ipv4.tcp_max_syn_backlog a menudo se revisan durante el ajuste de alto tráfico.
No copies valores grandes del kernel de ejemplos aleatorios sin probar. Un equipo pequeño que ejecuta un servidor API no necesita las mismas configuraciones que un nodo perimetral de CDN. Ajusta en pasos, mide y toma notas.
Hay otro detalle que confunde a la gente: el límite de conexión de Nginx no es el único límite de conexión en el camino. Un balanceador de carga en la nube tiene tiempos de espera de inactividad. Un tiempo de ejecución de contenedor puede tener límites de traducción de direcciones de red. La aplicación backend puede tener su propio grupo de trabajadores o grupo de conexiones de base de datos. Si Nginx puede aceptar 20,000 conexiones pero la aplicación puede procesar solo 200 solicitudes concurrentes, los usuarios seguirán esperando.
Es por eso que un cambio de ajuste de conexión debe incluir una verificación rápida de extremo a extremo. Ejecuta una pequeña prueba de carga desde un host fuera del servidor, observa las conexiones activas de Nginx y también observa el backend. Si la latencia del backend aumenta bruscamente mientras Nginx se mantiene tranquilo, el proxy está haciendo su trabajo y el siguiente límite está detrás de él.
Ajuste para Cargas de Trabajo de Proxy Inverso
Muchos servidores Nginx actúan como proxies inversos frente a servidores de aplicaciones. En ese rol, el comportamiento del upstream es tan importante como la capacidad de Nginx.
Usa keepalive del upstream cuando Nginx hable repetidamente con el mismo grupo de backend:
upstream app_backend {
server 127.0.0.1:3000;
keepalive 32;
}
server {
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://app_backend;
}
}
Esto reduce el costo de abrir nuevas conexiones de backend. Es especialmente útil cuando tu aplicación recibe muchas solicitudes pequeñas, como llamadas API desde un panel de control.
También verifica tus valores de tiempo de espera. Los tiempos de espera de proxy muy largos pueden mantener ocupadas las conexiones de trabajo después de que los clientes desaparezcan o las aplicaciones dejen de responder. Los tiempos de espera muy cortos pueden romper solicitudes lentas legítimas. Ajusta los valores de tiempo de espera a la carga de trabajo en lugar de usar un valor predeterminado en todas partes.
Un escenario práctico: tu sitio es rápido la mayor parte del día pero se ralentiza durante el envío de un boletín. La CPU está solo al 35%, pero los registros de Nginx muestran advertencias de conexión. Eso apunta lejos de la CPU bruta y hacia los límites de conexión, descriptores de archivos o colas del upstream. Aumentar las conexiones de trabajo puede ayudar, pero solo si la aplicación y el sistema operativo pueden soportar la carga adicional.
Otro escenario común es una aplicación de panel que realiza muchas llamadas API pequeñas desde cada pestaña del navegador. Diez personas pueden crear cientos de solicitudes cortas. En ese caso, el keepalive del upstream a menudo es más importante que simplemente aumentar worker_connections, porque la configuración repetida de TCP al backend se convierte en una sobrecarga innecesaria.
Para un servicio de descarga de archivos, la historia es diferente. Un pequeño número de usuarios puede mantener las conexiones abiertas durante mucho tiempo mientras descargan archivos grandes. Es posible que necesites suficientes conexiones de trabajo para transferencias de larga duración, pero también debes verificar sendfile, el rendimiento del disco, el rendimiento de la red y el comportamiento de tiempo de espera del cliente.
Para aplicaciones WebSocket o de sondeo largo, las conexiones inactivas son normales. Un número alto de Waiting no es automáticamente malo. La pregunta es si esas conexiones inactivas dejan suficiente capacidad para nuevas solicitudes y si el uso de la memoria se mantiene predecible.
Leer stub_status Mientras Ajustas
El módulo stub_status te brinda una vista rápida del comportamiento de la conexión:
Active connections: 291
server accepts handled requests
1162447 1162447 4496426
Reading: 6 Writing: 17 Waiting: 268
Reading significa que Nginx está leyendo los encabezados de la solicitud. Un número alto sostenido puede apuntar a clientes lentos, encabezados grandes o un patrón de ataque. Writing significa que Nginx está enviando respuestas. Esto puede aumentar cuando los clientes son lentos para recibir datos o cuando las respuestas son grandes. Waiting significa conexiones keepalive inactivas. Ese número puede ser alto en sitios saludables.
Los contadores accepts y handled generalmente deberían moverse juntos. Si las conexiones aceptadas aumentan pero las conexiones manejadas se quedan atrás o aparecen errores, verifica los límites de trabajo y los límites de descriptores de archivos. También verifica si el kernel está descartando conexiones antes de que Nginx pueda manejarlas.
Estos contadores son básicos, pero son útiles porque separan la presión de la conexión de la presión de la CPU. Si las conexiones activas son bajas y la CPU es alta, el problema probablemente no sea worker_connections. Si las conexiones activas son altas y la CPU es baja, los límites de conexión, el comportamiento keepalive, las colas del upstream o los clientes lentos se vuelven más probables.
Una Configuración de Línea Base Segura
Para un servidor de producción pequeño, prefiero comenzar de manera conservadora y medir:
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
}
http {
keepalive_timeout 30s;
keepalive_requests 1000;
}
Esta no es una configuración universalmente mejor. Es un punto de partida razonable para muchas cargas de trabajo normales de proxy inverso. Una VM muy pequeña puede necesitar menos. Un proxy perimetral ocupado puede necesitar mucho más. La parte importante es que worker_connections y worker_rlimit_nofile estén alineados.
Después de aplicar una línea base, compara las métricas antes y después durante un tráfico similar. No juzgues un cambio de ajuste por un minuto afortunado después de la recarga. Observa la latencia p95 o p99, la tasa de error, la CPU, la memoria y las colas del backend durante el tiempo suficiente para ver el comportamiento real.
Errores que Hacen que el Ajuste de Conexiones Parezca Aleatorio
El primer error es contar solicitudes en lugar de conexiones. Un navegador puede reutilizar una conexión para múltiples solicitudes, y HTTP/2 puede multiplexar muchas solicitudes en una sola conexión. Un cliente lento también puede mantener una conexión abierta mientras hace muy poco trabajo útil. Eso significa que "solo obtenemos 500 solicitudes por segundo" no te dice cuántas conexiones necesita Nginx.
El segundo error es olvidar las conexiones del upstream. Si Nginx sirve archivos estáticos, la mayoría de las conexiones son del lado del cliente. Si Nginx actúa como proxy de una aplicación, las solicitudes activas a menudo también necesitan sockets de backend. Si usas keepalive hacia el upstream, algunas conexiones de backend permanecen abiertas para su reutilización. Esto es bueno, pero aún consume descriptores de archivos en ambos lados.
El tercer error es aumentar los límites de Nginx sin verificar la aplicación. Supongamos que Nginx ahora puede aceptar 12,000 conexiones simultáneas, pero la aplicación tiene 16 procesos de trabajo y un grupo de base de datos de 50 conexiones. Nginx aceptará más trabajo del que la aplicación puede terminar. Los usuarios pueden ver menos errores de conexión inmediatos, pero la latencia puede empeorar porque las solicitudes esperan más tiempo en las colas.
El cuarto error es usar tiempos de espera keepalive largos en todas partes. Keepalive es útil porque evita la configuración repetida de TCP y TLS. Pero un tiempo de espera muy largo puede dejar muchos sockets inactivos abiertos después de un pico de tráfico. En un proxy perimetral con mucha memoria, esto puede estar bien. En una VM pequeña, puede desplazar el trabajo activo. Si ves un recuento enorme de Waiting y una baja reutilización de solicitudes, prueba un keepalive_timeout más corto y mide de nuevo.
Ejemplos de Solución de Problemas
Si el registro de errores dice worker_connections are not enough, verifica el valor configurado, el número de trabajadores y el límite de archivos del proceso:
grep -R "worker_connections\\|worker_processes\\|worker_rlimit_nofile" /etc/nginx/nginx.conf /etc/nginx/conf.d
cat /proc/$(pgrep -o nginx)/limits | grep "open files"
El comando pgrep -o nginx generalmente encuentra el proceso de Nginx más antiguo, que a menudo es el maestro. En algunos sistemas, puedes preferir systemctl status nginx para ver el PID principal.
Si el registro de errores dice too many open files, no solo aumentes worker_connections. El proceso está alcanzando su límite de descriptores. Agrega o ajusta LimitNOFILE para el servicio systemd, recarga systemd y reinicia Nginx para que el nuevo límite se aplique realmente:
sudo systemctl edit nginx
sudo systemctl daemon-reload
sudo systemctl restart nginx
Si los usuarios ven tiempos de espera pero Nginx tiene CPU libre y sin advertencias de conexión, mira detrás de Nginx. Verifica el tiempo de respuesta del upstream en los registros de acceso. Verifica el grupo de trabajadores de la aplicación. Verifica las conexiones de la base de datos. Un proxy inverso puede aceptar tráfico sin problemas mientras el verdadero cuello de botella es un backend saturado.
Si un pico causa restablecimientos de conexión antes de que las solicitudes aparezcan en los registros de acceso, el problema puede ser anterior al manejo de solicitudes de Nginx. Observa las configuraciones de backlog del kernel, los registros del balanceador de carga, las tablas de estado del firewall y la protección contra inundaciones SYN. Nginx no puede registrar una solicitud que nunca recibió.
Cómo Probar los Cambios de Forma Segura
Nunca ajustes la producción editando y esperando. Primero prueba la sintaxis:
sudo nginx -t
Luego recarga Nginx para que las conexiones activas se manejen de manera elegante:
sudo systemctl reload nginx
Observa el registro de errores después de cada cambio:
sudo tail -f /var/log/nginx/error.log
También debes monitorear la latencia de las solicitudes, las tasas de 4xx y 5xx, las conexiones activas, la CPU, la memoria y el tiempo de respuesta del upstream. Un cambio de ajuste que aumenta la capacidad de conexión pero aumenta la latencia de la aplicación puede no ser una victoria real.
Para pasos de validación más profundos, consulta cómo probar configuraciones de Nginx.
Cuándo Traer a un Especialista
Llama a un ingeniero DevOps experimentado o especialista en rendimiento web cuando los errores de Nginx continúen después del ajuste básico, cuando los picos de tráfico afecten los ingresos, o cuando estés cambiando la configuración de red del kernel en un sistema de producción. Lo mismo se aplica si estás ajustando Nginx frente a flujos de pago, sistemas de inicio de sesión o API críticas.
La ayuda profesional también es útil cuando el cuello de botella no está claro. Nginx puede parecer el problema cuando el problema real es una base de datos lenta, un grupo de aplicaciones upstream agotado, una capa de terminación TLS sobrecargada o un desajuste de tiempo de espera del balanceador de carga.
La conclusión clave es simple: ajusta los procesos de trabajo para que coincidan con la CPU, ajusta las conexiones de trabajo para que coincidan con la concurrencia y asegúrate de que los límites de archivos de Linux admitan ambos. Cambia una capa a la vez, prueba la configuración antes de recargar y mide el tráfico real en lugar de confiar en los máximos teóricos.