...

Optimización de las solicitudes Keepalive de NGINX: máximo rendimiento del servidor web mediante un ajuste específico

Con nginx keepalive Reduzco los costes de establecimiento de conexión, minimizo los intercambios de datos iniciales y acelero notablemente los tiempos de respuesta. Los tiempos de espera ajustados de forma específica, los límites de solicitudes por conexión y la reutilización de sockets de upstream proporcionan mejoras cuantificables en el rendimiento sin necesidad de nuevo hardware.

Puntos centrales

  • Tiempos muertos Elegir con sensatez: el tiempo de inactividad debe ser tan breve como sea necesario y tan largo como resulte útil.
  • Solicitudes Limitar por conexión: sockets duraderos, sin bloqueos.
  • Grupos de upstream Activar: Conexiones persistentes con el backend por trabajador.
  • Trabajador y ajustar las conexiones: suficientes ranuras para los clientes inactivos y activos.
  • Monitoreo Establecer: supervisar la tasa de conexión, la latencia y los errores.

NGINX Keepalive: efectos y costes

Mantengo abiertas las conexiones TCP a propósito porque Apretones de manos son costosas y predominan en muchas solicitudes pequeñas. Los sockets persistentes no solo ahorran RTT, sino que también suavizan la carga de la CPU, ya que la criptografía para TLS se activa con menos frecuencia. Sin embargo, cada conexión abierta ocupa Recursos, como los descriptores de archivo y los búferes, a los que debo prestar atención. El secreto está en encontrar el equilibrio: suficiente reutilización para garantizar la velocidad y suficiente «presupuesto» para nuevas conexiones en los picos de carga. Quien logre este equilibrio conseguirá valores de TTFB constantemente bajos y una experiencia de usuario ágil.

HTTP/2 y HTTP/3: el multiplexado se une al «keepalive»

Con HTTP/2 y HTTP/3 Se reduce el número de conexiones necesarias por cliente, ya que varios flujos se transmiten a través de una misma línea. No obstante, la función «Keepalive» sigue siendo importante: es necesario que al menos una conexión permanezca abierta de forma fiable; de lo contrario, la ventaja del multiplexado se esfuma debido a las frecuentes reconexiones.

Presto atención a los parámetros de inactividad específicos de los protocolos modernos y me aseguro de que los valores se ajusten a los tiempos de espera de mis clientes. Para las pruebas, empiezo con valores moderados y los voy aumentando cuando la carga se estabiliza, hasta que la tasa de reconexiones disminuye y las latencias se mantienen constantes.

http {
    # HTTP/2: tiempo de inactividad para flujos abiertos pero no utilizados
    http2_idle_timeout 60s;

    # HTTP/3/QUIC: lógica similar para conexiones basadas en UDP
    http3_idle_timeout 60s;

    # La reanudación de TLS reduce el coste del protocolo de enlace en las nuevas conexiones
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
}

El multiplexado reduce el número necesario de conexiones TCP/QUIC paralelas, pero no la importancia de las tiempos de espera correctos. Quienes utilizan HTTP/2/3 suelen poder establecer tiempos de espera del cliente algo más amplios, ya que muchos recursos pequeños circulan por el mismo canal. Importante: hay que poder seguir midiéndolos Tiempo hasta el primer byte, índices de error y flujos abiertos por conexión.

Configurar correctamente el «client keepalive»

En el caso de los clientes de navegador, gestiono la reutilización a través de tiempo de espera de keepalive y keepalive_requests, para que los sockets permanezcan activos el tiempo suficiente sin bloquearse indefinidamente. Como punto de partida, utilizo un tiempo de espera de entre 30 y 60 segundos y entre 100 y 300 solicitudes por conexión; después, lo ajusto en función de las métricas. En este enlace se ofrece una explicación detallada: Guía sobre el tiempo de espera de Keepalive, que explica las repercusiones en la latencia y los recursos del servidor. Los tiempos de espera más cortos son adecuados cuando hay un gran número de llamadas breves, mientras que los plazos más largos resultan útiles en el caso de accesos periódicos a la API. Para empezar, establezco unos valores predeterminados claros y mido el efecto sobre las conexiones abiertas y los tipos de error.

http {
    # Conexiones inactivas con el cliente
    keepalive_timeout 60s;
    # Límite máximo de solicitudes por conexión TCP
    keepalive_requests 200;

    # Opcional: desactivar Keep-Alive para determinados clientes (errores heredados)
    # keepalive_disable msie6;
}

Keepalive de upstream en el proxy inverso

Entre NGINX y las aplicaciones de backend utilizo sockets upstream persistentes, ya que la conexión con PHP-FPM, Node.js o los servicios de Python también Latencia cuesta. Para ello, activo en el pool de upstream un número adecuado de conexiones reutilizables por cada worker. Es importante utilizar HTTP/1.1 en la dirección de salida y un encabezado „Connection“ vacío; de lo contrario, la solicitud «close» del cliente interrumpe la persistencia del backend. Me baso en el número de solicitudes simultáneas y configuro el pool de tal forma que apenas se produzcan nuevas conexiones. De este modo, se reduce el tiempo de conexión del backend y toda la cadena ofrece un rendimiento más ágil. Respuestas.

upstream backend {
    server 127.0.0.1:9000;
    keepalive 64; # Número de conexiones persistentes de upstream por trabajador
}

server {
    location / {
 proxy_pass http://backend;
        proxy_http_version 1.1;
 proxy_set_header Connection "";
 # Keepalive TCP para sockets de upstream a nivel del sistema operativo
 proxy_socket_keepalive on;
    }
}

Dimensionamiento del grupo y presupuesto de conexiones

Calculo los pools de forma realista: el número de conexiones persistentes de origen se obtiene a partir de worker_processes × keepalive por cada servidor de origen. Si se utilizan 8 trabajadores y un keepalive de 64, se mantienen abiertos hasta 512 sockets por servidor de origen, por cada instancia. Detrás de un equilibrador de carga o con varios servidores de origen, esto puede sumar rápidamente.

Mi objetivo: disponer de suficientes sockets abiertos para que la mayor parte de las solicitudes sin el nuevo Connect se atiende, pero aún hay margen para picos. Superviso la métrica „nuevas conexiones de salida por segundo“ y la reduzco hasta que un aumento adicional del tamaño del pool ya no suponga una mejora apreciable de la latencia.

También tengo en cuenta Equidad: Las piscinas demasiado grandes pueden perjudicar a los clientes que acaban de llegar, ya que las ranuras de los trabajadores quedan ocupadas por conexiones inactivas. Un límite moderado con supervisión activa suele ser más rápido que establecer valores máximos a ciegas.

Ajuste preciso: tiempos de espera y límites de solicitudes

Combino el tiempo de espera y el límite de solicitudes de tal forma que las conexiones se reutilicen de manera efectiva sin llegar al Esquiador de fondo . Los valores altos en ambos ejes minimizan las conexiones, pero aumentan el riesgo de que los sockets se cuelguen en caso de problemas de red. Los valores bajos garantizan conexiones frescas, pero requieren más intercambios de datos. Voy avanzando poco a poco, observo los errores y realizo ajustes a intervalos regulares. La siguiente tabla muestra rangos iniciales recomendados para diferentes patrones de uso y ofrece una visión general compacta Orientación.

Escenario tiempo de espera de keepalive keepalive_requests Nota
Muchas visitas breves a la página 10-30 s 100-300 Reutilización rápida, bajo consumo en reposo
Página web típica 60-120 s 200–400 Un buen término medio para Assets y HTML
API con llamadas periódicas 60-120 s 300–1000 Mayor tasa de reutilización para los clientes
Servicios internos / Pasarelas 30-90 s 500–1000+ La constancia es más importante que las conexiones mínimas

Ajuste de los trabajadores y conexiones

Puse procesos_trabajadores en «auto» o en el número de núcleos de la CPU, y asegúrate de que haya suficientes conexiones_trabajadores porque los sockets inactivos ocupan ranuras. Unos límites demasiado bajos impiden que se acepten nuevas conexiones, aunque aún quede capacidad de CPU disponible. Quien utilice pools de keepalive grandes necesita suficientes descriptores y ranuras de eventos por cada worker. Una buena introducción la ofrece „Escalar las conexiones de los trabajadores“, que explica las relaciones entre eventos, conexiones y carga. Unos valores bien definidos garantizan que la reutilización en estado inactivo y las nuevas conexiones puedan coexistir.

worker_processes auto;

events {
    worker_connections 4096;
    # Opcional: reuseport puede mejorar la distribución a nivel del kernel
    # multi_accept on;
}

http {
    keepalive_timeout 60s;
    keepalive_requests 200;

 upstream backend {
 server 127.0.0.1:9000;
 keepalive 64;
    }
}

Optimización del sistema operativo y de los sockets

Compruebo los límites del sistema para que Keepalive pueda desarrollar todo su potencial. Un número insuficiente de descriptores o colas de sockets demasiado limitadas provocan cuellos de botella artificiales. Además de «ulimit» y «worker_rlimit_nofile», los límites del núcleo son fundamentales.

# Valores de sysctl de ejemplo (ajustar con precaución y tras realizar pruebas)
fs.file-max = 1000000
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 16384
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_syn_backlog = 262144

Ajusto estos valores en función del entorno: muchas conexiones de corta duración se benefician de un rango de puertos más amplio y de tiempos FIN/TIME_WAIT más cortos. En el caso del keepalive de upstream, reduzco Neuconnects, lo que reduce los picos de TIME_WAIT. Además, tengo en cuenta NAT-Dispositivos entre el proxy y el backend: unos tiempos de espera en reposo demasiado agresivos en la red cortan las conexiones de forma imprevista. Un límite moderado de peticiones por socket y los keepalives de TCP (proxy_socket_keepalive on;) evitan las conexiones „obsoletas“.

Configurar correctamente los encabezados y la versión HTTP

Presto atención a HTTP/1.1 al backend, ya que Upstream-Keepalive solo funciona así. Además, elimino el control activo de conexiones mediante encabezados, para que NGINX gestione la persistencia de forma autónoma. En el lado del cliente, dejo que Keep-Alive funcione según el estándar y limito su duración mediante el tiempo de espera (timeout) y el límite de solicitudes. Además, compruebo los tiempos de espera de inactividad del backend y los configuro ligeramente por encima de los de NGINX para evitar errores de reinicio. Unos encabezados limpios garantizan la Reutilice sin cierres involuntarios.

Ejemplo de #: ubicación de proxy con encabezados correctos
location /api/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
}

Diferencias: HTTP Keep-Alive frente a TCP Keep-Alive

Hago una distinción estricta entre HTTP Keep-Alive (varias solicitudes HTTP por conexión) y TCP-Keepalive (Pruebas a nivel del sistema operativo para detectar terminales inactivos). Controlo el Keep-Alive de HTTP con tiempo de espera de keepalive y keepalive_requests, mientras que los «keepalives» de TCP, dependiendo de la pila, se realizan a través de proxy_socket_keepalive on; y los parámetros del sistema. Para los backends que utilizan redes inestables, activo los «keepalives» de TCP para liberar más rápidamente los sockets bloqueados.

Aplicaciones de larga duración y casos especiales: WebSockets, SSE, gRPC

Los WebSockets y los eventos enviados por el servidor son Esquiador de fondo, que mantienen una conexión abierta durante mucho tiempo; en este caso, el «Reuse» clásico desempeña un papel secundario. Yo me encargo de encontrar las opciones adecuadas proxy_read_timeout y protégeme con send_timeout contra Slowloris-Efectos. En el caso de gRPC (basado en HTTP/2), hay que tener en cuenta las consideraciones relativas al multiplexado; configuro los tiempos de espera por inactividad de tal forma que los flujos no se cierren innecesariamente.

location /ws/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 300s;
    send_timeout 30s;
}

Seguimiento y métricas

Mido el éxito a través de indicadores como la tasa de nuevas conexiones upstream, hora_de_conexión_arriba y el porcentaje de conexiones abiertas por trabajador. Una disminución de las tasas de conexión, con un número de solicitudes constante o en aumento, indica que la reutilización se está llevando a cabo con éxito. Los tiempos de espera o los reinicios de conexión anómalos señalan tiempos de espera contradictorios entre NGINX y el backend. Además, superviso la memoria, los descriptores de archivos y las colas de eventos bajo carga. Quien realice comprobaciones periódicas detectará las tendencias a tiempo y evitará costosas Fallas.

Mejoras en el registro para una mayor transparencia en la reutilización

Para obtener más información, amplío el registro de acceso con datos sobre las conexiones. Así puedo ver con qué frecuencia se reutiliza una conexión TCP y cómo evolucionan los tiempos de conexión.

log_format keepalive_fmt
  '$remote_addr $host "$request" $status $body_bytes_sent '
  '$request_time $upstream_connect_time '
  'conn:$connection reqs:$connection_requests';

access_log /var/log/nginx/access_keepalive.log keepalive_fmt;

Analizo los valores de la mediana y de P95/P99 de hora_de_conexión_arriba así como la distribución de $_solicitudes_de_conexión. Un aumento en el número de repeticiones con una latencia estable indica que los grupos y los tiempos de espera se han seleccionado adecuadamente.

Obstáculos típicos y soluciones

Las colas demasiado grandes ocupan ranuras de conexión mientras los nuevos clientes esperan, por lo que mantengo los tamaños moderados y los mido. Los diferentes tiempos de espera en inactividad entre el proxy y el backend provocan reinicios, así que configuro el backend con un valor mínimamente superior a NGINX. Un „Connection: close“ olvidado en el encabezado del proxy interrumpe la persistencia, por lo que vacío el encabezado de forma sistemática. La negociación TLS puede suponer una carga para la CPU cuando se establecen muchas conexiones nuevas, lo que mitigo aumentando la proporción de reutilización. En caso de fallos esporádicos de red, resulta útil establecer un límite moderado de solicitudes por socket, de modo que las antiguas Sesiones No vivimos para siempre.

Configuraciones prácticas

Para sitios web con mucho tráfico, elijo un tiempo de espera corto y un límite de solicitudes medio-alto, para que los recursos funcionen de forma eficiente. En el caso de las API con llamadas recurrentes, aumento el límite para reducir aún más los handshakes TCP y TLS. Dimensiono los grupos de servidores de origen en función de la paralelización prevista y los pruebo con tráfico realista. Cada entorno se comporta de forma diferente, por lo que, tras realizar cambios, compruebo la latencia y los patrones de error. Dos ejemplos lo ilustran: Valores iniciales, que luego perfecciono con métricas.

# Escenario 1: Sitio web con mucho tráfico
http {
    keepalive_timeout 30s;
    keepalive_requests 300;

 upstream app {
 server 127.0.0.1:8080;
        keepalive 32;
    }

 server {
 listen 443 ssl http2;
 Control del tiempo de inactividad de HTTP/2 en #
 http2_idle_timeout 45s;
    }
}
Escenario # 2: API con llamadas periódicas
http {
    keepalive_timeout 75s;
    keepalive_requests 1000;

    upstream api_backend {
 server 127.0.0.1:9001;
 keepalive 64;
    }

    server {
 listen 443 ssl http2;
 # Ventana de inactividad algo más larga para llamadas recurrentes
 http2_idle_timeout 75s;
    }
}

Lista de comprobación para la optimización iterativa

Empiezo con un análisis de la situación actual: los patrones de tráfico, los tiempos de respuesta y la tasa de errores marcan el ritmo. A continuación, configuro el tiempo de espera del cliente y el límite de solicitudes con valores iniciales sólidos y activo los grupos de servidores upstream. Configuro los tiempos de espera de inactividad del backend un poco más altos que en NGINX, para evitar que se produzcan Restablecimientos aparecen. A continuación, superviso las tasas de conexión, el tiempo de conexión y los sockets abiertos por trabajador. Quien quiera profundizar en el grado de reutilización encontrará sugerencias sobre Reutilización de conexiones y límites máximos razonables.

Diagnóstico adicional: desajustes y comportamiento temporal

Cuando las conexiones se interrumpen aparentemente „sin motivo“, busco Desajustes en la cadena: inactividad del cliente frente a tiempo de espera de NGINX frente a inactividad del backend y NAT/gateways intermedios. Aumento ligeramente el tiempo de espera del backend por encima del valor de NGINX, compruebo los códigos de reinicio en el registro de errores y observo si hora_de_conexión_arriba muestra picos. A menudo basta con un pequeño margen (por ejemplo, +10–20%) en el tiempo de espera del backend para eliminar los reinicios.

Además, tengo en cuenta que „acercamiento prolongado“Fases de cierre: al cerrar una conexión, NGINX deja que los datos entrantes se descarguen brevemente, lo que ocupa recursos de los trabajadores. Un gran número de cierres simultáneos puede bloquear eventos. En tales casos, calibro los intervalos de cierre y mantengo equilibrado el número total de conexiones abiertas mediante valores de keepalive adecuados.».

Resumen: El «keepalive» como factor clave para mejorar el rendimiento

Utilizo Keepalive de forma específica porque reduce los costes de establecimiento de conexión, disminuye la latencia y alivia la carga de la CPU. La combinación de un tiempo de espera adecuado, un límite de peticiones bien definido y unos grupos de servidores de origen adecuados aporta mejoras notables Velocidad. Sin un seguimiento, el potencial queda sin aprovechar, por lo que reviso continuamente los indicadores y ajusto los valores paso a paso. Quien necesite reservas adicionales debe prestar atención al número de trabajadores, a los slots de conexión y al tratamiento correcto de los encabezados. Las configuraciones profesionales, por ejemplo, en webhoster.de, aprovechan al máximo estas posibilidades y ofrecen servicios rápidos y fiables.

Artículos de actualidad