Volver al blog

Síguenos y suscríbete

Reutilizar las conexiones backend para aumentar el rendimiento

Rogier Mulhuijzen

Senior Professional Services Engineer

Reutilizar las conexiones entre tu instancia de Varnish y tus backends (orígenes) es una buena idea por múltiples razones. Si tu Varnish está en la misma red que tus backends y tienes un tráfico de bajo volumen, puedes dejar de leer, porque a) la diferencia probablemente será insignificante, y b) probablemente ya estés reutilizando conexiones de backend.

Para saber si las conexiones se están reutilizando o no, usa el siguiente comando:

me@example:~$ varnishstat -1 -f backend_conn,backend_reuse
backend_conn          3881846        4.22 Backend conn. success
backend_reuse       191288113      208.34 Backend conn. reuses

La primera columna es el nombre de la estadística, siendo backend_conn es el número de veces que se ha realizado una conexión y backend_reuse es cuántas veces se ha reutilizado. La segunda columna es el valor desde que se inició tu Varnish y la tercera columna es el promedio por segundo durante ese periodo.

Lo que estás buscando es que backend_reuse no sea cero, e idealmente sea un orden de magnitud, o mejor, mayor que backend_conn. Los valores del ejemplo anterior son bastante ideales. Realiza la conexión ocasional, pero la gran mayoría de las solicitudes se realizan a través de conexiones ya existentes.

También puedes ejecutar el comando varnishstat sin el -1 y te dará una columna adicional, que mostrará el cambio en los valores durante el último segundo.

Antes de profundizar en cómo puedes mejorar estos números si son malos, repasemos algunas de las razones por las que reutilizar es una buena idea.

¿Por qué reutilizar las conexiones?

Como mencioné anteriormente, hay dos condiciones en las que la reutilización es importante. La principal es si el tiempo de ida y vuelta (RTT) entre tu Varnish y los backends es alto. La otra es ejecutar un sitio de alto tráfico, con miles de solicitudes por segundo. Si tienes un RTT que está por debajo de un milisegundo, encontrarás que las mejoras de la reutilización de las conexiones son mínimas, pero debido al alto volumen, las pequeñas mejoras pueden tener un gran impacto.

Empezaré, sin embargo, con la razón más importante: puedes quedarte sin números de puerto. Cada conexión se identifica de manera única mediante una tupla que consta de las IP de origen y destino, así como los puertos de origen y destino. De esos cuatro, solo el puerto de origen no es estático entre tu Varnish y un solo backend. Por lo general, hay miles de puertos disponibles (y con algunos ajustes de tu sistema operativo, aproximadamente 64 K). Cuando se cierra una conexión, tu sistema operativo mantendrá la tupla entre 30 segundos y 2 minutos, y se negará a usar esa misma tupla para cualquier conexión nueva para evitar que los datos retrasados lo echen todo a perder. Estas conexiones están en el estado denominado TIME_WAIT. La mayoría de los sistemas operativos te permiten ajustar cuánto tiempo permanecen las conexiones en TIME_WAIT después de que se cierran, pero no se recomienda reducir ese valor, y puedes evitar el problema reutilizando las conexiones.

Un poco de matemática de servilleta muestra que si has ajustado tu sistema operativo para usar todos los números de puerto superiores a 1024 para las conexiones salientes y tu sistema operativo mantiene las conexiones cerradas en el estado TIME_WAIT durante 60 segundos, puedes hacer aproximadamente 1066 conexiones por segundo a un solo backend antes de quedarte sin puertos.

La segunda razón para reutilizar las conexiones es el coste de hacer la conexión. En el lado de la red, se necesita un viaje de ida y vuelta antes de que se pueda enviar una solicitud. Pero incluso si eso no es un problema porque tu RTT es bajo, aún requiere un poco de esfuerzo de tu sistema operativo. Además de algunos búferes, también tienes que asignar un descriptor de archivo, que generalmente requiere una búsqueda lineal para encontrar el número más bajo disponible, y no se puede paralelizar. En los indicadores que he visto, la reutilización de conexiones marca una diferencia del 300-400 % en el rendimiento, y eso sucedió con Varnish y los backends en la misma red local.

La tercera razón es el escalado de la ventana TCP. Mientras se usa una conexión TCP, ambos extremos ajustan la ventana de congestión (cantidad de datos permitidos en el cable a la vez) para permitir mayores velocidades de transferencia si es posible. Por supuesto, cuanto mayor sea el RTT, mayor será el impacto, pero incluso en una red local sigue siendo importante para archivos de varios megabytes. Al reutilizar las conexiones, las solicitudes anteriores generalmente habrán provocado que la ventana haya alcanzado su punto óptimo y las respuestas se transferirán tan rápido como lo permita tu red.

Cómo asegurarse de que las conexiones se reutilicen

Hay varios elementos clave para verificar, si ves que las conexiones no se reutilizan lo suficiente.

La versión del protocolo

En primer lugar, asegúrate de que tus backends sean compatibles con HTTP/1.1. Parece bastante sorprendente, pero 16 años después de la introducción de HTTP/1.1, todavía nos encontramos con servidores HTTP/1.0 circulando libremente.

Para verificar si tus servidores están respondiendo con HTTP/1.1 o HTTP/1.0, usa el siguiente comando:

me@example:~$ varnishtop -b -i RxProtocol

La -b filtra el registro de Varnish solo para las comunicaciones de backend. El -i RxProtocol lo reduce aún más a solo la parte del protocolo de la respuesta.

Deberías ver algo como:

list length 2                                    example

  6612.25 RxProtocol        HTTP/1.1
     1.82 RxProtocol        HTTP/1.0

Los números reflejan cuántas veces en el último minuto se vio cierta línea en el registro. Obviamente solo nos gustaría ver HTTP/1.1, pero todavía puede ocurrir el falso HTTP/1.0 ocasional. Si la relación es similar al ejemplo anterior, entonces no tienes nada de qué preocuparte. No necesariamente estás buscando la perfección aquí.

Sin embargo, si ves una mayor cantidad de solicitudes HTTP/1.0 de las que deseas, puedes usar el siguiente comando para ver todas las transacciones de backend que tienen una respuesta HTTP/1.0:

me@example:~$ varnishlog -b -m RxProtocol:HTTP/1.0

Una de las cosas a tener en cuenta es BackendOpen. Eso le da el nombre del backend en tu VCL, así como las direcciones IP y los puertos de la conexión. También verás todos los encabezados de solicitud y respuesta.

Cómo hacer que tu backend responda usando HTTP/1.1 depende completamente de tu backend. Consulta tu documentación o ponte en contacto con el proveedor. Actualizar a una versión más reciente del software en cuestión también puede ayudar.

Conexiones persistentes

HTTP/1.1 considera todas las conexiones persistentes (que se pueden reutilizar) a menos que se marque explícitamente lo contrario. El encabezado utilizado para marcar una conexión como no persistente es Connection: close. Para ver cuántos encabezados Connection: close obtienes por segundo, puedes usar:

me@example:~$ varnishtop -bC -i RxHeader -I connection.*close

Para ver esas transacciones en detalle:

me@example:~$ varnishlog -bC -m RxHeader:connection.*close

Nuevamente, hacer que tu backend deje de enviar los encabezados Connection: close y reutilice las conexiones es algo muy específico. Consulta la documentación, ponte en contacto con el proveedor y considera actualizar.

Número máximo de solicitudes

Algunos servidores web solo harán un cierto número de solicitudes por conexión. Cuando se alcance el máximo, enviarán un encabezado Connection: close y cerrarán la conexión después de que se complete la respuesta.

Apache, por ejemplo, tiene la configuración MaxKeepAliveRequests cuyo valor predeterminado es 100. Establecer esto en 0 le permitirá a Apache gestionar un número infinito de solicitudes en una conexión.

Tiempos de espera de conexión persistente

Para conservar los recursos, los servidores web cierran las conexiones después de haber estado inactivas durante un tiempo. Esto a menudo se conoce como el tiempo de espera de conexión persistente. Por defecto, Varnish cerrará las conexiones de los clientes después de 10 segundos sin actividad y Apache después de 5 segundos. Por el contrario, Varnish mantendrá las conexiones a los backends abiertas durante el mayor tiempo posible. Si clientes aleatorios (es decir usuarios en Internet) no pueden conectarse directamente a su backend, realmente no hay una buena razón para mantener corto el tiempo de espera de mantenimiento. Piensa en minutos en vez de segundos.

En Apache, la configuración es KeepAliveTimeout, y la mayoría de otros software tendrán algo parecido a eso.

Tiempos de espera de dispositivos de red

Algo que debe tenerse en cuenta es que puede haber firewalls con control de estado o dispositivos NAT entre tu Varnish y tus backends. Estos también tienden a tener tiempos de espera en las conexiones TCP. Si esos son más bajos que el tiempo de espera de mantenimiento en tus backends, los dispositivos de red no sabrán qué hacer con el tráfico en la conexión que Varnish está tratando de reutilizar. La descartarán y provocarán tiempos de espera, o enviarán reinicios y harán que Varnish vuelva a intentar la solicitud si es posible.

Verifica toda la ruta de red entre tu Varnish y tus backends, y asegúrate de que los tiempos de espera para las conexiones abiertas sean más altos que el tiempo de espera de conexión persistente de tus backends.

TL;DR

La reutilización de las conexiones beneficia enormemente el rendimiento entre tu Varnish y tus backends. Asegúrate de no estar utilizando HTTP/1.0, de que tus backends no envíen encabezados Conexión: cierre, de aumentar los tiempos de espera y de verificar los tiempos de espera de la red en todos los dispositivos de la ruta.