...

Keep Alive Webserver: configurar correctamente el freno silencioso del rendimiento

El servidor web Keep Alive suele determinar el tiempo de espera o la velocidad: si está mal configurado, ralentiza silenciosamente, pero si está bien ajustado, acelera notablemente cada solicitud. Voy a mostrar concretamente cómo lo hago. Keep-Alive Configurar qué franjas horarias funcionan y por qué las que están abiertas demasiado tiempo TCP-Las conexiones cuestan rendimiento.

Puntos centrales

  • mecanismo: Las conexiones TCP abiertas ahorran handshakes y reducen la latencia.
  • valores fundamentales: Seleccionar KeepAliveTimeout, MaxKeepAliveRequests y activación de forma específica.
  • Carga del servidor: Las ventanas de tiempo correctamente ajustadas reducen los requisitos de CPU y RAM.
  • Práctica: Tener en cuenta sistemáticamente el comportamiento del navegador y las cadenas de proxy inverso.
  • Controlar: Medir, ajustar, volver a medir, hasta dar con el punto óptimo.

Qué hace Keep Alive

En lugar de iniciar cada solicitud con un nuevo handshake, Keep-Alive mantiene la TCP-Conexión abierta y atiende varias solicitudes a través de ella. En un escenario con 50 solicitudes por segundo de tres clientes, el flujo de paquetes se reduce drásticamente: de unos 9000 a unos 540 paquetes por minuto, porque se crean menos conexiones y se ejecutan menos handshakes. Esto reduce los tiempos de espera y ahorra ciclos de servidor, lo que tiene efectos directos en Tiempo de carga y rendimiento. En las pruebas, el tiempo se reduce a la mitad, pasando de unos 1190 ms a unos 588 ms, es decir, en más de un 50 %, siempre que el resto de la cadena no esté limitada. Por eso, siempre incluyo Keep-Alive desde el principio en la configuración y controlo las latencias reales en el tráfico en vivo.

Las cifras clave adecuadas

Empezaré con los tres ajustes que siempre funcionan: activación, número de solicitudes por conexión y intervalo de tiempo hasta el cierre de la Conexión. La activación decide si se produce la reutilización; el número máximo de solicitudes controla cuánto tiempo permanece abierta una conexión; el tiempo de espera equilibra la economía y la capacidad de respuesta. Un intervalo de tiempo demasiado largo bloquea las ranuras y desperdicia RAM, porque los sockets inactivos permanecen y faltan trabajadores. Un intervalo demasiado corto anula las ventajas, ya que el servidor se desconecta demasiado pronto y tiene que volver a arrancar. Me ciño a los valores predeterminados ajustados y solo los aumento cuando las mediciones confirman tiempos de espera reales en reposo.

HTTP/1.1 frente a HTTP/2/3: clasificación

Keep-Alive funciona por conexión TCP. En HTTP/1.1, varias solicitudes comparten una línea sucesivamente, mientras que en HTTP/2 se comparten varias. Transmisiones multiplexado a través de una única conexión, HTTP/3 utiliza QUIC en lugar de TCP. Yo lo clasificaría así: un tiempo de espera breve sigue siendo útil incluso con HTTP/2, ya que las transmisiones inactivas no son gratuitas: la conexión sigue consumiendo recursos, especialmente en TLS. Nginx tiene su propia ventana de inactividad para HTTP/2; me aseguro de que los valores globales de Keep-Alive y los valores límite específicos de HTTP/2 coincidan entre sí y no sean arbitrariamente altos. Importante: Nginx solo se comunica actualmente con el cliente HTTP/2; con el backend mantiene HTTP/1.1-Conexiones abiertas. Por lo tanto, Upstream-Keepalive sigue siendo obligatorio para mantener la ventaja de extremo a extremo. En HTTP/3 se aplican principios similares: aunque QUIC oculta mejor las pérdidas, un canal abierto durante mucho tiempo y sin utilizar consume memoria y descriptores de archivos. Por lo tanto, mi enfoque sigue siendo conservador: ventanas de inactividad cortas, límites claros y, mejor, una reconexión limpia que una retención interminable.

La sobrecarga de TLS desde un punto de vista pragmático

TLS aumenta aún más el ahorro gracias a Keep-Alive, ya que los handshakes son más caros que las conexiones TCP puras. Con TLS 1.3 y Session-Resumption, la carga se reduce, pero en total se gana con cada nueva conexión que se evita. En la práctica, compruebo tres puntos: en primer lugar, si el servidor utiliza correctamente la reanudación de sesión (no dejar que los tickets caduquen demasiado pronto). En segundo lugar, si los cifrados fuertes y los protocolos modernos están activos sin forzar innecesariamente a los clientes antiguos. En tercer lugar, si la utilización de la CPU se mantiene estable con un alto grado de paralelismo. Incluso con la reanudación, los intervalos de tiempo de mantenimiento de conexión cortos y estables evitan picos adicionales de CPU, ya que se inician menos negociaciones. Al mismo tiempo, con intervalos demasiado largos no impido los handshakes, sino que desplazo la carga a la inactividad, lo cual es la opción más cara.

Apache: configuración recomendada

En Apache, activo KeepAlive en En, establece MaxKeepAliveRequests en 300-500 y selecciona un intervalo de tiempo de 2-3 segundos en la mayoría de los casos. El valor 0 para el número máximo de solicitudes parece tentador, pero ilimitado rara vez tiene sentido, ya que las conexiones tardan demasiado en establecerse. pegar. Para aplicaciones muy frecuentadas con clientes estables, pruebo entre 5 y 10 segundos; en picos con muchas visitas breves, reduzco a 1-2 segundos. Lo importante es: primero ajustar el tiempo de espera y luego ajustar con más precisión el número de solicitudes, para que las ranuras no se bloqueen por inactividad. Si no tienes acceso a la configuración principal, puedes controlar el comportamiento de la conexión por directorio mediante mod_headers, siempre que el proveedor de alojamiento haya habilitado esta opción.

Nginx: ajuste razonable

En Nginx, Keep-Alive está activado de forma predeterminada, por lo que presto especial atención al tiempo de espera, las excepciones del navegador y el número por conexión. Con keepalive_timeout, establezco los segundos abiertos, que ajusto gradualmente de 1 a 5 segundos según el patrón de tráfico; con muchas llamadas a la API, también pueden ser útiles 10 segundos. Con keepalive_disable excluyo los clientes antiguos problemáticos para que no causen problemas. Sesiones . En los proxies inversos a los upstreams, también utilizo upstream keepalive para que Nginx reutilice las conexiones con el backend y ocupe menos trabajadores allí. De esta manera, mantengo la ruta consistente de extremo a extremo y evito separaciones en medio del flujo de solicitudes.

Proxy inverso y reenvío de encabezados

En configuraciones de varios niveles, necesito una Estrategia, que transmite correctamente los encabezados HTTP/1.1 y no sobrescribe accidentalmente los valores de conexión. Nginx debería comunicarse con el backend en HTTP/1.1 y tolerar explícitamente Keep-Alive, mientras que Apache utiliza los intervalos de tiempo adecuados detrás. Son críticas las configuraciones que fuerzan Connection: close o interfieren con las rutas de actualización, ya que entonces la supuesta ganancia se esfuma. En Apache, puedo controlar mediante mod_headers por ubicación si las conexiones permanecen abiertas y qué información adicional se establece. Todos los nodos deben perseguir el mismo objetivo, de lo contrario, un eslabón genera el efecto de frenado, que en realidad quería evitar.

CDN, equilibradores de carga y configuraciones en la nube

Si hay una CDN o un equilibrador de carga delante, la mayoría de las conexiones de los clientes terminan allí. El origen se beneficia entonces sobre todo de unas pocas conexiones permanentes entre el borde y el origen. Me aseguro de que el equilibrador también funcione con ventanas de inactividad cortas y de que el agrupamiento de conexiones al backend esté activado. En entornos de contenedores y en la nube, también es importante el flujo de drenaje: antes de una actualización continua, envío el nodo al Drenaje-Estado, dejo que las conexiones abiertas expiren rápidamente (tiempo de espera no demasiado alto) y solo entonces inicio el reemplazo. De esta manera evito solicitudes interrumpidas y conexiones zombis restantes. Las sesiones persistentes (por ejemplo, mediante cookies) pueden dividir los grupos de conexiones; siempre que es posible, apuesto por conexiones de bajo estado. Backends o almacenes de sesiones externos, para que la reutilización se aplique de manera uniforme.

Velocidad de alojamiento en la práctica

Muchos entornos compartidos desactivan Keep-Alive para obtener un rendimiento a corto plazo. Tragamonedas ahorrar, pero las páginas se vuelven lentas y pierden la sensación de interacción. Por eso, compruebo desde el principio con pruebas de tiempo de carga si el servidor permite la reutilización y cómo se ven las fases de conexión en el diagrama de cascada. Si la herramienta detecta bloques de handshake largos entre muchos activos pequeños, suele faltar la reutilización o el tiempo de espera se interrumpe demasiado pronto. Para un ajuste más preciso, me ayuda una guía estructurada como esta compacta Ajuste de Keep Alive, para poder trabajar los pasos con precisión. Así evito las conjeturas y consigo un resultado notable con pocos movimientos. impulso en la parte delantera.

Tiempo de espera, límites y comportamiento del navegador

Los navegadores modernos abren varias ventanas paralelas por cada host. Conexiones, a menudo seis, y agotan rápidamente la capacidad de Keep Alive. En la práctica, un MaxKeepAliveRequests de 300 es suficiente para muchos visitantes simultáneos, siempre que el tiempo de espera no sea innecesariamente alto. Si establezco la ventana en tres segundos, las ranuras permanecen disponibles y el servidor da prioridad a los clientes activos en lugar de a los inactivos. Solo cuando las solicitudes se interrumpen con regularidad o la reutilización no funciona, aumento el límite en niveles moderados. Las páginas con muchos flujos HTTP/2 requieren una consideración especial. Los detalles se resumen en Multiplexación HTTP/2 muy compacto, para que pueda clasificar claramente el uso del canal y el keep-alive.

Parámetros Directiva Apache Directiva Nginx valor indicativo Nota
Activación KeepAlive activado activo por defecto activar siempre Sin reutilización, aumenta Sobrecarga.
Tiempo de espera Tiempo de espera de KeepAlive tiempo de espera de keepalive 2-5 s Más corto en muchas llamadas cortas, más largo en APIs.
Número/Conn MaxKeepAliveRequests keepalive_requests 300-500 Limita el compromiso de recursos por cada Cliente.
Excepciones del navegador - keepalive_disable selectiva Desactivar para muy antiguos Clientes.
aguas arriba ProxyKeepAlive mantenimiento de conexión ascendente activo Asegura la reutilización Dirección Backend.

Límites del sistema operativo y sockets

A nivel del sistema operativo, los descriptores de archivos y los parámetros de socket limitan la capacidad real. Compruebo ulimit -n, los límites del proceso y del sistema, así como la configuración del servidor web (por ejemplo, worker_connections en Nginx). Aunque Keep-Alive reduce el número de nuevas conexiones, aumenta el tiempo durante el cual los descriptores permanecen ocupados. En fases de mucho tráfico, puede producirse presión TIME_WAIT si las conexiones se cierran muy rápidamente; en este caso, lo más útil es una reutilización limpia en lugar de agresivos hacks del kernel. Distingo claramente entre HTTP-Keep-Alive (protocolo de aplicación) y las pruebas TCP Keepalive del núcleo: estas últimas son paquetes puramente de señal de vida, que no deben confundirse con la ventana HTTP abierta. Solo modifico los valores predeterminados del núcleo con un punto de medición y me centro principalmente en el propio servidor web: tiempos de espera de inactividad cortos pero eficaces, solicitudes limitadas por conexión y reservas de trabajadores razonables.

Seguridad: Slowloris & Co. desactivan

Los valores de Keep-Alive demasiado generosos invitan al abuso. Por lo tanto, no solo limito los tiempos de inactividad, sino también los tiempos de espera de lectura y del cuerpo. En Nginx utilizo client_header_timeout y client_body_timeout; en Apache, establezco límites de lectura estrictos mediante los módulos adecuados para que las solicitudes lentas no bloqueen los trabajadores. Los límites para el tamaño de los encabezados y los cuerpos de las solicitudes también evitan el aumento excesivo de la memoria. Junto con ventanas de keep-alive moderadas, reduzco el riesgo de que unos pocos clientes ocupen muchos sockets. El orden sigue siendo importante: primero, tiempos de espera correctos; luego, límites específicos; y, por último, reglas relacionadas con la tasa o la IP. Solo así los usuarios reales siguen siendo rápidos, mientras que los perfiles de ataque no llegan a nada.

Monitorización y pruebas de carga

Después de cada cambio, mido el efecto con herramientas como ab, wrk o k6 y miro el percentil 95 de la Latencias. Primero reduzco el tiempo de espera en pasos claros y observo si aumentan los tiempos de espera o las interrupciones de conexión; luego ajusto el número de solicitudes por conexión. Al mismo tiempo, evalúo los sockets abiertos, la carga de trabajo y los requisitos de memoria para eliminar el tiempo de inactividad en el lugar adecuado. Para los tiempos de espera recurrentes, vale la pena echar un vistazo a las colas en el backend, palabra clave Cola de servidores y distribución de solicitudes. Quienes trabajan con puntos de medición detectan rápidamente los cuellos de botella y se ahorran mucho tiempo. Solución de problemas.

Práctica de registros y métricas

Quiero ver si las conexiones realmente se reutilizan. En Nginx, amplío el formato del registro con contadores de conexiones y tiempos; los valores me muestran si los clientes envían muchas solicitudes por conexión o si cierran después de uno o dos accesos. Hago lo mismo en Apache para ver el número de solicitudes por conexión. Así identifico patrones que se benefician más del tiempo de espera o del límite de solicitudes.

# Nginx: ejemplo de formato de registro ampliado log_format main_ext '$remote_addr $request ' 'conn=$connection reqs=$connection_requests ' 'rt=$request_time uct=$upstream_connect_time';

access_log /var/log/nginx/access.log main_ext;
# Apache: LogFormat con conexión y duración LogFormat "%h %r conn:%{c}L reqs:%{REQUESTS_PER_CONN}n time:%D" keepalive CustomLog logs/access_log keepalive

En el monitoreo, además de la mediana, me interesan sobre todo las latencias P95/P99, las conexiones activas, la distribución de las solicitudes/conexiones y los errores (aumento de 408/499). Si estos aumentan con una ventana Keep-Alive más pequeña, reduzco moderadamente; si la carga se mantiene estable y la latencia mejora, he dado en el punto óptimo.

Implementación y reinicios progresivos

Las recargas y actualizaciones son compatibles con Keep-Alive si las planifico correctamente. Con Nginx, apuesto por recargas fluidas y dejo que las conexiones de los trabajadores se procesen de forma controlada, en lugar de cortarlas bruscamente. Los tiempos de espera de inactividad cortos ayudan a que los antiguos trabajadores se liberen más rápidamente. Con Apache, utilizo un elegante-Reinicia y observa paralelamente mod_status o las páginas de estado para que las solicitudes en espera no se interrumpan. Antes de implementaciones importantes, reduzco temporalmente la ventana Keep-Alive para vaciar el sistema más rápidamente y, tras comprobar la estabilidad, la vuelvo a subir al valor objetivo. Importante: documenta los cambios y compáralos con los perfiles de carga para que no pasen desapercibidos los lentos Regresiones colarse.

Errores frecuentes y medidas correctivas

Los intervalos de tiempo demasiado largos mantienen inactivos Conexiones abiertos y trasladan el problema a cuellos de botella de los trabajadores, lo que frena notablemente a los nuevos visitantes. Las solicitudes ilimitadas por conexión parecen elegantes, pero al final aumenta la vinculación por socket y los picos de carga se descontrolan. Las ventanas extremadamente cortas, de menos de un segundo, hacen que los navegadores se reconstruyan continuamente, lo que aumenta las proporciones de handshake y hace que el frontend parezca entrecortado. Las cadenas de proxy suelen carecer de consistencia: un eslabón utiliza HTTP/1.0 o establece Connection: close, lo que impide la reutilización. Por lo tanto, trabajo en orden: compruebo la activación, ajusto los tiempos de espera en pequeños pasos, adapto las solicitudes por conexión y solo las aumento cuando las mediciones muestran un aumento real. Beneficio espectáculo.

Lista de comprobación para una rápida implementación

Primero activo Keep-Alive y anoto los datos actuales. Valores, para poder volver atrás en cualquier momento. A continuación, establezco el tiempo de espera en tres segundos, vuelvo a cargar la configuración y compruebo las conexiones abiertas, la carga y las cascadas en el frontend. Si hay muchas visitas breves, lo reduzco a dos segundos; si se acumulan las API Long Polls, lo aumento moderadamente a entre cinco y diez segundos. A continuación, establezco MaxKeepAliveRequests en 300-500 y observo si quedan ranuras libres o si los clientes permanentes fuertes se conectan durante demasiado tiempo. Después de cada paso, vuelvo a medir, documento los efectos y mantengo el mejor Combinación fijo.

Balance corto

Un Keep-Alive correctamente configurado ahorra handshakes, reduce la latencia y proporciona más al servidor. Aire por solicitud. Con intervalos de tiempo cortos, pero no demasiado, y un número moderado de solicitudes por conexión, el host funciona de forma notablemente más fluida. Apuesto por pequeños cambios con puntos de medición claros, en lugar de ajustar a ciegas los valores máximos. Quien orienta el alojamiento, el proxy inverso y el backend de forma coherente hacia la reutilización, gana en interacción rápida sin una vinculación innecesaria de recursos. Al final, lo que cuenta es la medición: solo las cifras reales muestran si el ajuste ha tenido el efecto deseado. Efecto trae.

Artículos de actualidad