Lista Esencial de Optimización de Rendimiento de Nginx para Sitios Web de Alto Tráfico
Una lista práctica de verificación de rendimiento de Nginx para trabajadores, conexiones, búferes, almacenamiento en caché, compresión, registros, tiempos de espera, TLS y archivos estáticos.
Lista Esencial de Optimización de Rendimiento de Nginx para Sitios Web de Alto Tráfico
La optimización del rendimiento de Nginx es más fácil cuando la tratas como una lista de verificación, no como un juego de adivinanzas. Comienza con los límites que determinan cuánto tráfico puede aceptar Nginx, luego avanza hacia el almacenamiento en búfer, el almacenamiento en caché, la compresión, el registro, los tiempos de espera, TLS y los servicios backend detrás de él.
No pegues todas las directivas aquí en producción de una vez. Una buena lista de verificación de optimización de rendimiento de Nginx te ayuda a decidir qué verificar, por qué es importante y qué puede salir mal si te excedes. La configuración correcta para un sitio de documentación mayormente estático no es la misma que para una API de sondeo largo o un servicio de carga de archivos.
1. Optimizar Procesos de Trabajo y Conexiones
Nginx aprovecha un modelo de proceso maestro-trabajador. El proceso maestro lee la configuración y gestiona los procesos de trabajo, que manejan las solicitudes reales de los clientes. Configurar correctamente estos puede mejorar drásticamente la concurrencia y la utilización de recursos.
worker_processes
Esta directiva determina cuántos procesos de trabajo generará Nginx. Generalmente, establecerlo en auto permite que Nginx detecte el número de núcleos de CPU y genere un número igual de procesos de trabajo, lo cual es una práctica común recomendada.
worker_connections
Define el número máximo de conexiones simultáneas que un solo proceso de trabajo puede abrir. Esta configuración, junto con worker_processes, dicta el total teórico de conexiones concurrentes que Nginx puede manejar (worker_processes * worker_connections).
multi_accept
Permite que un proceso de trabajo acepte múltiples conexiones nuevas a la vez, evitando posibles cuellos de botella bajo alta carga.
# /etc/nginx/nginx.conf
worker_processes auto; # Generalmente se establece en 'auto' o el número de núcleos de CPU
events {
worker_connections 1024; # Ajustar según la capacidad del servidor y la carga esperada
multi_accept on;
}
Consejo: Si la CPU está constantemente alta, aumentar
worker_connectionsno lo solucionará por sí solo. Primero confirma si la CPU proviene de los handshakes TLS, la compresión, el registro, el enrutamiento con muchas expresiones regulares o la aplicación upstream.
2. Gestión Eficiente de Conexiones
Optimizar cómo Nginx maneja las conexiones de red puede reducir la sobrecarga y mejorar la capacidad de respuesta.
keepalive_timeout
Especifica cuánto tiempo permanecerá abierta una conexión keep-alive del cliente. Reutilizar conexiones reduce la sobrecarga de establecer nuevas conexiones TCP y handshakes SSL. Un valor común es de 15 a 65 segundos, dependiendo de la interactividad de tu aplicación.
sendfile
Habilita la transferencia directa de datos entre descriptores de archivo, evitando el almacenamiento en búfer del espacio de usuario. Esto mejora significativamente el rendimiento al servir archivos estáticos.
tcp_nopush
Funciona con sendfile. Nginx intenta enviar el encabezado HTTP y el inicio del archivo en un solo paquete. Después de eso, envía datos en paquetes completos. Esto reduce el número de paquetes enviados.
tcp_nodelay
Indica a Nginx que envíe datos tan pronto como estén disponibles, sin almacenarlos en búfer. Esto es beneficioso para aplicaciones interactivas donde la baja latencia es más crítica que maximizar el rendimiento (por ejemplo, aplicaciones de chat o actualizaciones en tiempo real).
http {
keepalive_timeout 65; # Conexiones keep-alive durante 65 segundos
sendfile on;
tcp_nopush on; # Requiere sendfile activado
tcp_nodelay on; # Útil para proxy de contenido dinámico
}
3. Optimización de Búferes
Nginx utiliza búferes para manejar las solicitudes de los clientes y las respuestas de los servidores upstream (como los servidores de aplicaciones). Dimensionar correctamente estos búferes puede evitar E/S de disco innecesarias, reducir el uso de memoria y mejorar el rendimiento.
Búferes del Cliente
client_body_buffer_size: Tamaño del búfer para los cuerpos de las solicitudes del cliente. Si un cuerpo excede esto, se escribe en un archivo temporal.client_header_buffer_size: Tamaño del búfer para la primera línea y los encabezados de una solicitud del cliente.large_client_header_buffers: Define el número y tamaño de los búferes más grandes para leer los encabezados de las solicitudes del cliente. Útil para solicitudes con muchas cookies o encabezados referer largos.
Búferes de Proxy (para configuraciones de proxy inverso)
proxy_buffers: El número y tamaño de los búferes utilizados para leer las respuestas del servidor proxy.proxy_buffer_size: El tamaño del primer búfer para leer la respuesta. Generalmente más pequeño, ya que a menudo solo contiene encabezados.proxy_busy_buffers_size: La cantidad máxima de búferes de respuesta que pueden estar en estado 'ocupado' (enviándose activamente al cliente) en un momento dado.
Búferes FastCGI (para PHP-FPM, etc.)
fastcgi_buffers: El número y tamaño de los búferes utilizados para leer las respuestas del servidor FastCGI.fastcgi_buffer_size: El tamaño del primer búfer para leer la respuesta.
http {
# Búferes del Cliente
client_body_buffer_size 1M; # Ajustar según el tamaño esperado del cuerpo de la solicitud (por ejemplo, cargas de archivos)
client_header_buffer_size 1k;
large_client_header_buffers 4 8k; # 4 búferes, cada uno de 8KB
# Búferes de Proxy (si Nginx actúa como proxy inverso)
proxy_buffers 8 16k; # 8 búferes, cada uno de 16KB
proxy_buffer_size 16k; # Primer búfer de 16KB
proxy_busy_buffers_size 16k; # Máximo 16KB de búferes ocupados
# Búferes FastCGI (si Nginx trabaja con PHP-FPM)
fastcgi_buffers 16 16k; # Punto de partida para muchas aplicaciones PHP-FPM
fastcgi_buffer_size 16k; # Primer búfer de 16KB
}
Advertencia: Establecer búferes demasiado pequeños puede provocar E/S de disco y degradación del rendimiento. Configurarlos demasiado grandes puede consumir memoria excesiva. Encuentra un equilibrio mediante pruebas.
4. Implementar Estrategias Robustas de Almacenamiento en Caché
El almacenamiento en caché es una de las formas más efectivas de mejorar el rendimiento y reducir la carga en tus servidores backend. Nginx puede servir como un potente caché de contenido.
proxy_cache_path
Define la ruta al directorio de caché, su tamaño, el número de niveles de subdirectorios y cuánto tiempo permanecen los elementos inactivos en la caché.
proxy_cache
Activa el almacenamiento en caché para un bloque de location dado, haciendo referencia a la zona definida en proxy_cache_path.
proxy_cache_valid
Establece el tiempo durante el cual Nginx debe almacenar en caché las respuestas con códigos de estado HTTP específicos.
proxy_cache_revalidate
Cuando está habilitado, Nginx utilizará los encabezados If-Modified-Since e If-None-Match para revalidar el contenido en caché con el backend, reduciendo el uso de ancho de banda.
proxy_cache_use_stale
Indica a Nginx que sirva contenido en caché obsoleto si el servidor backend está caído, no responde o experimenta errores. Esto mejora enormemente la disponibilidad.
expires
Establece los encabezados Cache-Control y Expires para el almacenamiento en caché del lado del cliente de archivos estáticos. Esto minimiza las solicitudes repetidas a Nginx.
http {
# Define una zona de caché de proxy en el bloque http
proxy_cache_path /var/cache/nginx/my_cache levels=1:2 keys_zone=my_cache:10m inactive=60m max_size=10g;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://my_upstream_backend;
proxy_cache my_cache; # Habilita el almacenamiento en caché para esta ubicación
proxy_cache_valid 200 302 10m; # Almacena en caché respuestas exitosas durante 10 minutos
proxy_cache_valid 404 1m; # Almacena en caché 404s durante 1 minuto
proxy_cache_revalidate on;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
add_header X-Cache-Status $upstream_cache_status; # Ayuda con la depuración
}
# Almacena en caché archivos estáticos en el navegador por un período más largo
location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
expires 30d; # Almacena en caché durante 30 días
add_header Cache-Control "public, no-transform";
# Para archivos estáticos, considera servirlos directamente desde Nginx si no están proxy
root /var/www/html;
}
}
}
5. Habilitar Compresión Gzip
Comprimir las respuestas antes de enviarlas a los clientes puede reducir significativamente el uso de ancho de banda y mejorar los tiempos de carga de la página, especialmente para contenido basado en texto.
gzip on
Activa la compresión gzip.
gzip_comp_level
Establece el nivel de compresión (1-9). El nivel 1 es el más rápido con menos compresión; el nivel 9 es el más lento con la máxima compresión. El nivel 6 suele ofrecer un buen equilibrio.
gzip_types
Especifica los tipos MIME que deben comprimirse. Incluye tipos comunes de texto, CSS, JavaScript y JSON.
gzip_min_length
Establece la longitud mínima de una respuesta (en bytes) para la cual se debe habilitar la compresión. Los archivos pequeños no se benefician mucho e incluso podrían ser más lentos debido a la sobrecarga de compresión.
gzip_proxied
Indica a Nginx que comprima las respuestas incluso si son proxy. any es un valor común.
gzip_vary
Agrega el encabezado Vary: Accept-Encoding a las respuestas, informando a los proxies que la respuesta puede diferir según el encabezado de solicitud Accept-Encoding.
http {
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6; # Nivel de compresión 1-9 (6 es un buen equilibrio)
gzip_buffers 16 8k; # 16 búferes, cada uno de 8KB
gzip_http_version 1.1; # Versión HTTP mínima para compresión
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
gzip_min_length 1000; # Solo comprimir respuestas mayores de 1KB
}
6. Optimizar el Registro
Si bien los registros son esenciales para la monitorización y la resolución de problemas, un registro excesivo o no optimizado puede introducir una E/S de disco significativa, especialmente en sitios de alto tráfico.
access_log
- Deshabilitar para activos estáticos: Para contenido estático muy accedido (imágenes, CSS, JS), deshabilitar
access_logpuede ahorrar mucha E/S. - Almacenamiento en búfer: Nginx puede almacenar en búfer las entradas de registro en memoria antes de escribirlas en disco, reduciendo la frecuencia de las escrituras en disco. Los parámetros
bufferyflushse utilizan aquí.
error_log
Establece el nivel de registro apropiado (crit, error, warn, info, debug). Para producción, warn o error suele ser suficiente para capturar problemas críticos sin inundar los registros.
http {
server {
# Registro de acceso predeterminado para contenido dinámico
access_log /var/log/nginx/access.log main;
location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
access_log off; # Deshabilitar el registro para archivos estáticos comunes
expires 30d;
}
}
# Ejemplo de registro de acceso con búfer para el contexto HTTP principal
# access_log /var/log/nginx/access.log main buffer=16k flush=5s;
error_log /var/log/nginx/error.log warn; # Solo registrar advertencias y superiores
}
7. Ajustar Tiempos de Espera
Los tiempos de espera configurados adecuadamente evitan que Nginx mantenga conexiones inactivas demasiado tiempo, liberando recursos.
Tiempos de Espera del Lado del Cliente
client_body_timeout: Cuánto tiempo espera Nginx a que un cliente envíe el cuerpo de la solicitud.client_header_timeout: Cuánto tiempo espera Nginx a que un cliente envíe el encabezado de la solicitud.send_timeout: Cuánto tiempo espera Nginx a que un cliente acepte la respuesta después de enviarla.
Tiempos de Espera de Proxy/FastCGI (si corresponde)
proxy_connect_timeout: Tiempo de espera para establecer una conexión con un servidor proxy.proxy_send_timeout: Tiempo de espera para transmitir una solicitud al servidor proxy.proxy_read_timeout: Tiempo de espera para leer una respuesta del servidor proxy.
http {
client_body_timeout 15s; # El cliente tiene 15 segundos para enviar el cuerpo
client_header_timeout 15s; # El cliente tiene 15 segundos para enviar los encabezados
send_timeout 15s; # Nginx tiene 15 segundos para enviar la respuesta al cliente
# Para escenarios de proxy
proxy_connect_timeout 5s; # 5 segundos para conectarse al upstream
proxy_send_timeout 15s; # 15 segundos para enviar la solicitud al upstream
proxy_read_timeout 15s; # 15 segundos para leer la respuesta del upstream
# Para escenarios FastCGI
fastcgi_connect_timeout 5s;
fastcgi_send_timeout 15s;
fastcgi_read_timeout 15s;
}
8. Optimización SSL/TLS
Para sitios habilitados para HTTPS, optimizar la configuración SSL/TLS es crucial para reducir la sobrecarga de la CPU y mejorar el rendimiento del handshake.
ssl_session_cache y ssl_session_timeout
Habilitar el almacenamiento en caché de sesiones SSL para evitar el costoso handshake TLS completo para conexiones posteriores del mismo cliente.
ssl_protocols y ssl_ciphers
Usar protocolos TLS modernos como TLSv1.2 y TLSv1.3. Ten cuidado con las cadenas de cifrado copiadas: los cifrados TLS 1.3 no se controlan de la misma manera que los conjuntos de cifrado TLS más antiguos, y los valores predeterminados de la distribución suelen ser más seguros que los ejemplos obsoletos de guías antiguas.
ssl_stapling
Habilita el grapado OCSP, donde Nginx obtiene periódicamente la respuesta OCSP de la CA y la "grapa" al handshake SSL/TLS. Esto reduce la latencia del lado del cliente al evitar una consulta OCSP separada.
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/your_domain.crt;
ssl_certificate_key /etc/nginx/ssl/your_domain.key;
ssl_session_cache shared:SSL:10m; # Caché compartida para 10MB de datos de sesión
ssl_session_timeout 10m; # Las sesiones expiran después de 10 minutos
ssl_protocols TLSv1.2 TLSv1.3; # Usar protocolos modernos y seguros
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s; # Usar resolutores aprobados para tu entorno
resolver_timeout 5s;
}
9. Caché de Archivos Abiertos
Nginx puede almacenar en caché los descriptores de archivos para archivos accedidos con frecuencia, reduciendo la necesidad de llamadas al sistema repetidas para abrir y cerrar archivos.
open_file_cache
Habilita la caché, especificando el número máximo de elementos y cuánto tiempo permanecen los elementos inactivos.
open_file_cache_valid
Establece con qué frecuencia la caché debe verificar la validez de sus elementos.
open_file_cache_min_uses
Especifica el número mínimo de veces que un archivo debe ser accedido dentro del tiempo inactive para permanecer en la caché.
open_file_cache_errors
Determina si Nginx debe almacenar en caché los errores al abrir archivos.
http {
open_file_cache max=100000 inactive=60s; # Almacenar en caché hasta 100,000 descriptores de archivo durante 60s
open_file_cache_valid 80s; # Verificar validez cada 80 segundos
open_file_cache_min_uses 1; # Almacenar en caché archivos usados al menos una vez
open_file_cache_errors on; # Almacenar en caché errores relacionados con la apertura de archivos
}
10. Validar con Señales de Tráfico Real
El último elemento de la lista de verificación es la medición. Antes de un cambio, captura una pequeña línea base: latencia de solicitud, tasa de 5xx, conexiones activas, CPU, memoria, E/S de disco, rendimiento de red y tiempo de respuesta del upstream. Después del cambio, compara los mismos números.
Para un proxy inverso, $request_time y $upstream_response_time son especialmente útiles. Si ambos aumentan juntos, el backend probablemente es lento. Si $request_time es alto mientras que el tiempo del upstream es bajo o vacío, observa la velocidad de carga del cliente, el tiempo de transferencia de la respuesta, el almacenamiento en búfer, la compresión o la entrega de archivos estáticos. Si ninguna métrica explica el problema, verifica el registro de errores y el sistema operativo.
La secuencia de ajuste más segura es simple: probar la configuración con nginx -t, recargar en lugar de reiniciar cuando sea posible, monitorear los registros y retroceder rápidamente si la latencia o los errores se mueven en la dirección incorrecta. Nginx puede manejar mucho tráfico, pero solo cuando sus límites, el kernel y la aplicación upstream están de acuerdo entre sí.