Conexiones HTTP persistentes y rendimiento web

NGINX | 14 de marzo de 2014

¿Alguna vez ha evaluado el rendimiento de un servidor en el laboratorio y, tras ponerlo en producción con tráfico real, ha descubierto que ni siquiera se acerca al rendimiento obtenido en las pruebas? El uso de la CPU es bajo y hay muchos recursos disponibles, pero los clientes se quejan de que los tiempos de respuesta son lentos y usted no sabe cómo aprovechar mejor el servidor.

Lo que está observando es uno de los efectos de lo que podemos denominar «trabajo pesado de HTTP». En esta entrada del blog, analizamos cómo funciona HTTP y cómo procesan las transacciones HTTP los servidores HTTP habituales. Examinamos algunos de los problemas de rendimiento que pueden surgir y vemos cómo el modelo basado en eventos de NGINX lo convierte en un proxy de aceleración muy eficaz para estos servidores HTTP. Con NGINX, puede mejorar el rendimiento en entornos reales hasta recuperar el nivel obtenido en sus pruebas de rendimiento locales.

Para obtener recomendaciones sobre cómo optimizar Linux y NGINX para mejorar la velocidad y la escalabilidad de sus aplicaciones, consulte Optimización de NGINX para mejorar el rendimiento en nuestro blog.

Introducción a HTTP y a las conexiones persistentes

Las conexiones persistentes HTTP son una función de rendimiento esencial que reduce la latencia y permite que las páginas web se carguen más rápido.

HTTP es un protocolo sencillo basado en texto. Si aún no lo has hecho, echa un vistazo a la salida de una herramienta de depuración de HTTP, como la incluida en tu navegador web, y observa la estructura estándar de las solicitudes y respuestas:

En su implementación más sencilla, un cliente HTTP crea una nueva conexión TCP con el servidor de destino, envía la solicitud y recibe la respuesta. A continuación, el servidor cierra la conexión TCP para liberar recursos.

Este modo de funcionamiento puede ser muy ineficiente, especialmente en páginas web complejas con un gran número de elementos o cuando las conexiones de red son lentas. Para establecer una nueva conexión TCP se requiere un «protocolo de enlace de tres vías», y para cerrarla también es necesario un procedimiento de cierre de dos vías. Crear y cerrar repetidamente conexiones TCP, una por cada mensaje, es como colgar y volver a marcar cada vez que una persona habla durante una conversación telefónica.

HTTP utiliza un mecanismo denominado «conexiones persistentes» para mantener abierta la conexión TCP entre el cliente y el servidor una vez finalizada una transacción HTTP. Si el cliente necesita realizar otra transacción HTTP, puede utilizar la conexión persistente inactiva en lugar de crear una nueva conexión TCP.

Por lo general, los clientes abren varias conexiones TCP simultáneas con un servidor y realizan transacciones persistentes (keepalive) a través de todas ellas. Estas conexiones se mantienen abiertas hasta que el cliente o el servidor decide que ya no son necesarias, normalmente como consecuencia de que se agote el tiempo de espera por inactividad.

Los navegadores web modernos suelen abrir entre 6 y 8 conexiones persistentes y mantenerlas abiertas durante varios minutos antes de cerrarlas por inactividad. Los servidores web pueden configurarse para que agoten el tiempo de espera de estas conexiones y las cierren antes.

¿Qué efecto tienen las conexiones persistentes en el servidor HTTP?

Si muchos clientes utilizan conexiones persistentes HTTP y el servidor web tiene un límite de concurrencia o un problema de escalabilidad, el rendimiento se desploma cuando se alcanza dicho límite.

El enfoque anterior está diseñado para ofrecer el mejor rendimiento posible a cada cliente. Por desgracia, en una situación similar a la «tragedia de los comunes», si todos los clientes actúan de este modo, el rendimiento de muchos servidores web y aplicaciones web habituales puede verse perjudicado.

El motivo es que muchos servidores tienen un límite fijo de concurrencia. Por ejemplo, en configuraciones habituales, el servidor HTTP Apache solo puede procesar un número limitado de conexiones TCP simultáneas: 150 con el módulo de multiprocesamiento (MPM) worker y 256 con el MPM prefork. Cada conexión HTTP persistente inactiva ocupa una de estas ranuras de concurrencia y, una vez que todas están ocupadas, el servidor no puede aceptar más conexiones HTTP.

La recomendación habitual es desactivar las conexiones persistentes en el servidor web o limitar su duración a un periodo muy breve. Estas ofrecen un vector muy sencillo para los ataques de denegación de servicio SlowHTTPTest y Slowloris (para obtener una solución rápida, consulte Protección contra ataques de denegación de servicio Keep‑Dead en serverfault.com).

Además, estos servidores web y de aplicaciones suelen asignar un hilo o proceso del sistema operativo a cada conexión. Una conexión TCP es un objeto muy ligero del sistema operativo, pero un hilo o proceso consume muchos recursos. Los hilos y procesos requieren memoria, el sistema operativo debe gestionarlos activamente y el «cambio de contexto» entre hilos o procesos consume CPU. Asignar a cada conexión su propio hilo o proceso es sumamente ineficiente.

El gran número de conexiones simultáneas de clientes y la asignación de un hilo o proceso a cada conexión dan lugar al fenómeno conocido como «trabajo pesado de HTTP», por el que se requiere un esfuerzo desproporcionadamente grande para procesar una transacción HTTP ligera.

¿Qué significa esto en la práctica?

No hacen falta muchos clientes para agotar el límite de concurrencia de muchos servidores web y de aplicaciones actuales.

Si un cliente abre 8 conexiones TCP y mantiene cada una activa durante 15 segundos después del último uso, ocupa 8 ranuras de concurrencia durante 15 segundos. Si los clientes llegan a su sitio web a un ritmo de 1 por segundo, las conexiones persistentes inactivas ocupan continuamente 120 ranuras de concurrencia. Si el ritmo es de 2 clientes por segundo, se ocupan 240 ranuras de concurrencia. Una vez agotadas las ranuras, los nuevos clientes no pueden conectarse hasta que las conexiones existentes caduquen.

Esto puede dar lugar a niveles de servicio muy desiguales. Los clientes que consiguen establecer una conexión persistente pueden navegar libremente por su servicio. Los clientes que intentan conectarse cuando todas las ranuras de concurrencia están ocupadas no pueden acceder y tienen que esperar en una cola.

¿Por qué no se observan estos efectos durante las pruebas de rendimiento?

Estos problemas solo se manifiestan en redes lentas con muchos clientes. No aparecen al realizar pruebas de rendimiento con un único cliente a través de una red local rápida.

Hay un par de razones por las que puede que estos efectos no se observen en una prueba de rendimiento.

  • Si no habilita las conexiones persistentes durante la prueba de rendimiento, el cliente crea una nueva conexión TCP para cada transacción (y la conexión se cierra una vez finalizada la transacción). Como lo más probable es que ejecute la prueba en una red local rápida, esta se completa correctamente y no se aprecian los problemas de rendimiento derivados de no utilizar conexiones persistentes.
  • Si habilita las conexiones persistentes, lo más probable es que pueda ejecutar menos conexiones simultáneas que el límite de su servidor y que el cliente de pruebas de rendimiento sature cada conexión (utilizándola repetidamente), llevando al servidor a su capacidad máxima. Sin embargo, esto no refleja el perfil de conexiones del mundo real.

Tenga en cuenta que la mayoría de las herramientas de evaluación comparativa solo informan de las transacciones realizadas correctamente. Es posible que no se informe de las conexiones bloqueadas por el agotamiento de recursos, o que estas parezcan representar solo una fracción mínima de las conexiones establecidas correctamente. Esto oculta la verdadera naturaleza del problema con el tráfico real.

¿Hasta qué punto es común este problema?

Cualquier servidor web o de aplicaciones basado en hilos o procesos es vulnerable a las limitaciones de concurrencia.

Este problema es inherente a cualquier plataforma web o de aplicaciones que asigne un hilo o proceso a cada conexión. No es fácil detectarlo en un entorno optimizado de pruebas de rendimiento, pero en un entorno real se manifiesta en forma de bajo rendimiento y un uso excesivo de la CPU.

Hay varias medidas que puede tomar para solucionar este problema:

  • Aumente el número de hilos o procesos. Esta es una medida a muy corto plazo. Los hilos y los procesos son objetos pesados del sistema operativo y, a medida que se crean más, la sobrecarga de gestión aumenta rápidamente.
  • Deshabilite o limite el uso de conexiones persistentes HTTP: esto retrasa el momento en que se alcanza el límite de concurrencia, pero reduce considerablemente el rendimiento de cada cliente.
  • Utilice un procesamiento especializado de conexiones persistentes: Apache HTTP Server (servidor web) dispone de un MPM event relativamente nuevo que transfiere las conexiones entre los hilos de trabajo y un hilo de eventos dedicado cuando pasan de un estado «activo» a uno de «conexión persistente inactiva», y viceversa. Esta puede ser una opción si los demás módulos que utiliza son compatibles con este MPM; tenga en cuenta que las conexiones SSL/TLS se siguen procesando íntegramente en hilos dedicados.
  • Utilice un modelo de procesamiento más eficiente – Con diferencia, la medida más sencilla y eficaz que puede adoptar es colocar un proxy HTTP eficiente delante de sus servidores web o de aplicaciones. Un proxy basado en eventos como NGINX no presenta las limitaciones de concurrencia descritas anteriormente. Gestiona sin problemas las conexiones lentas y las conexiones persistentes inactivas. Además, transforma eficazmente las conexiones lentas del lado del cliente con múltiples conexiones persistentes inactivas en conexiones rápidas, locales y altamente eficientes, similares a las de las pruebas de rendimiento, que permiten obtener el máximo rendimiento posible de sus servidores web y de aplicaciones.

Utilice NGINX como proxy HTTP de aceleración

NGINX utiliza una arquitectura diferente que no se ve afectada por los problemas de concurrencia descritos anteriormente. Transforma las conexiones lentas de los clientes en conexiones optimizadas, similares a las de las pruebas de rendimiento, para obtener el máximo rendimiento de sus servidores.

NGINX utiliza un modelo basado en eventos de gran eficiencia para gestionar las conexiones.

Cada proceso de NGINX puede gestionar varias conexiones al mismo tiempo. Cuando se acepta una nueva conexión, la sobrecarga es muy baja (consiste en un nuevo descriptor de archivo y un nuevo evento que supervisar), a diferencia del modelo por proceso o por hilo descrito anteriormente. NGINX cuenta con un bucle de eventos muy eficaz:

Esto permite que cada proceso de NGINX pueda escalar fácilmente para gestionar decenas, miles o cientos de miles de conexiones simultáneas.

A continuación, NGINX reenvía las solicitudes al servidor de origen mediante un grupo local de conexiones persistentes. De este modo, se evita la sobrecarga que supone abrir y cerrar conexiones TCP, y las pilas TCP se adaptan rápidamente al tamaño de ventana y a los parámetros de reintento óptimos. La escritura de solicitudes y la lectura de respuestas son mucho más rápidas a través de la red local optimizada:

El efecto neto es que el servidor de origen se comunica con un único cliente local (NGINX) a través de una red rápida, y este cliente aprovecha de forma óptima las conexiones persistentes HTTP para minimizar el establecimiento de conexiones sin mantenerlas abiertas innecesariamente. Esto devuelve al servidor a un entorno óptimo, similar al de las pruebas de rendimiento.

Con NGINX actuando como proxy HTTP, se observa lo siguiente:

  • Mejor aprovechamiento de los recursos existentes. Sus servidores web y de aplicaciones pueden procesar más transacciones por segundo porque ya no tienen que encargarse de la pesada carga de trabajo de HTTP.
  • Reducción de las tasas de error. Es mucho menos probable que se agote el tiempo de espera de las solicitudes HTTP, ya que NGINX actúa como planificador central para todos los clientes.
  • Mejor rendimiento para el usuario final. Los servidores funcionan de forma más eficiente y atienden las conexiones con mayor rapidez.

Otras formas en que NGINX puede acelerar los servicios

Liberar a su infraestructura de aplicaciones sobrecargada de la pesada carga del procesamiento HTTP es solo una de las medidas con las que NGINX puede transformar su rendimiento.

La función de almacenamiento en caché HTTP de NGINX puede almacenar en caché las respuestas de los servidores ascendentes y aplicar la semántica estándar de caché para controlar qué se almacena y durante cuánto tiempo. Si varios clientes solicitan el mismo recurso, NGINX puede responder desde su caché y evitar sobrecargar los servidores ascendentes con solicitudes duplicadas.

NGINX también puede descargar otras operaciones del servidor de origen. Puede descargar las operaciones de compresión de datos para reducir el uso del ancho de banda, centralizar el cifrado y descifrado SSL/TLS, realizar la autenticación inicial de los clientes (por ejemplo, mediante la autenticación básica HTTP, las subsolicitudes a servidores de autenticación externos y los tokens web JSON) y aplicar todo tipo de reglas para limitar la tasa de tráfico cuando sea necesario.

No es el típico balanceador de carga ni ADC

Por último, no olvide que, a diferencia de otros proxies de aceleración, balanceadores de carga o controladores de entrega de aplicaciones (ADC), NGINX también es un servidor web completo. Puede utilizar NGINX para servir contenido estático, reenviar tráfico a servidores de aplicaciones para Java, PHP, Python, Ruby y otros lenguajes, distribuir contenido multimedia (audio y vídeo), integrarse con sistemas de autenticación y seguridad e incluso responder directamente a transacciones mediante reglas incorporadas en la configuración de NGINX.

Sin limitaciones de rendimiento integradas, NGINX y NGINX Plus aprovechan al máximo el hardware en el que se implementan, tanto ahora como en el futuro.

Para probar NGINX Plus, inicie hoy mismo su prueba gratuita de 30 días o póngase en contacto con nosotros para hablar sobre sus casos de uso.


Compartir
Etiquetas: F5 NGINX, Tech, 2014

Sobre el autor

Owen Garrett
Owen GarrettDirector sénior de Gestión de Producto

Más artículos de Owen Garrett

Artículos relacionados del blog

Únete a F5 NGINX en AppWorld 2024
NGINX | 04/01/2024

Únete a F5 NGINX en AppWorld 2024

Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.

Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
NGINX | 26/09/2023

Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source

La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.

Exposición de APIs en Kubernetes
NGINX | 10/03/2022

Exposición de APIs en Kubernetes

La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».

NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
NGINX | 23/08/2021

NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto

Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.

Presentamos NGINX Plus R22
NGINX | 09/06/2020

Presentamos NGINX Plus R22

NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.

Presentamos NGINX Plus R17
NGINX | 11/12/2018

Presentamos NGINX Plus R17

NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.