Cache de contenidos web con Varnish

Cuando trabajamos con servidores web con mucho tráfico, ya sea porque son máquinas con varias páginas web compartidas, o porque se esperan muchas peticiones a una web, o simplemente porque la página tiene un contenido muy pesado, podemos mejorar la experiencia del usuario implementando un sistema de cache de contenidos web y aquí es donde Varnish viene en nuestra ayuda.

Varnish es un sistema que trabaja delante de un servidor web guardando una copia, en memoria o en disco, del contenido estático de la página (normalmente imágenes, texto, css, jsp…) y lo sirve al usuario sin necesidad de pasar la petición al servidor web “real”. Este sistema es especialmente útil cuando la página usa un sistema CMS (Joomla, Moodle, Drupal, Magento…) ya que estos sistemas suelen ser bastante pesados para los servidores web, sobretodo cuando no se parametrizan correctamente o se cargan de módulos sin control.

Podéis leer más acerca de Varnish en su página web https://www.varnish-cache.org/

Normalmente la cache de contenidos se suele montar en un servidor independiente al que lleva la página web. En ese servidor se sincronizan, o se copian regularmente, los contenidos estáticos de la página y se sirven con un apache httpd o con un nginx (que es mucho mejor sirviendo este tipo de contenido) al estilo de un CDN, pero con una sola máquina. Gracias a esto podemos hacer que más gente pueda ver la web al mismo tiempo sin que el servidor caiga, ya que separamos la carga de red y de proceso entre dos o más servidores.

Si queremos mejorar el rendimiento de la página web sin necesidad de montar un CDN podemos hacerlo de una forma muy sencilla: simplemente instalando Varnish en nuestro servidor, configurado para escuchar las peticiones de los usuarios y derivarlas al servidor web real. A continuación pongo un ejemplo de configuración básica, pero efectiva, con un servidor Apache httpd y la cache con Varnish en una distribución Debian:

El esquema básico de lo que queremos montar es este:

Esquema Varnish

Esquema varnish

Configuración de Apache httpd

Si no se cambia su configuración Apache está configurado para escuchar en el puerto 80 (el puerto web por defecto) pero en este caso quien va a atender a las peticiones será Varnish accediendo únicamente a Apache cuando el contenido no se encuentre en cache.

Por esta razón lo primero que vamos a hacer es cambiar el puerto de escucha de Apache por el 8888, y lo dejaremos accesible únicamente desde “localhost”:

Cambiamos el puerto de escucha:

root@testvarnish:~# vim /etc/apache2/ports.conf
....
 #NameVirtualHost *:80
 #Listen 80
 NameVirtualHost 127.0.0.1:8888
 Listen 127.0.0.1:8888
.....

Modificamos todos los VirtualHost para que reflejen el cambio del puerto:

root@testvarnish:~# vim /etc/apache2/sites-enabled/000-default
#<VirtualHost *:80>
 <VirtualHost 127.0.0.1:8888>
 ServerAdmin webmaster@localhost
...

Reiniciamos el servicio para aplicar los cambios:

root@testvarnish:~# service apache2 restart

Comprobamos que todo está como esperamos:

root@testvarnish:~# netstat -lnp
 Active Internet connections (only servers)
 Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
 tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1570/sshd
 tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN 6527/apache2
 tcp6 0 0 :::22 :::* LISTEN 1570/sshd

Hay que recordar editar todos los “VirtualHosts” correspondientes para que también concuerden con el puerto nuevo, sino el servidor arrancará pero no servirá ninguna página.

Si no lo hacemos, al reiniciar el servicio, veremos un mensaje como el siguiente:

[warn] NameVirtualHost 127.0.0.1:8888 has no VirtualHosts

Configuración de Varnish

Para configurar el arranque y funcionamiento de varnish hay dos ficheros de configuración que es necesario modificar. En el primero configuraremos, principalmente, la cantidad de memoria RAM que asignaremos para cache (512Mb en este caso) y el puerto en el que escuchará el proceso (80, el web por defecto).

root@testvarnish:~# vim /etc/default/varnish
...
DAEMON_OPTS="-a :80 \
 -T localhost:6082 \
 -f /etc/varnish/default.vcl \
 -S /etc/varnish/secret \
 -s malloc,512m"
...

En el segundo fichero indicaremos donde tiene que realizar las peticiones, es decir, donde está el servidor web “real” que en nuestro caso es el apache que hemos configurado previamente para escuchar en el puerto 8888 de la propia máquina.

root@testvarnish:~# vim /etc/varnish/default.vcl
backend default {
 .host = "127.0.0.1";
 .port = "8888";
}
...

Este último fichero permite muchas configuraciones gracias a las reglas VCL (Varnish Control Language).

Estas reglas aportan una gran potencia al servicio, permitiendo realizar balanceos entre servidores web (con pesos, fail-over, condicionados a un nombre de host…), servir contenido de cache si todos los servidores web fallan, reglas de reescritura de URL (al estilo de mod_rewrite), selección de contenido dependiendo del navegador y muchas más.

Explicar el funcionamiento de todas ellas me podría llevar otro artículo, así que mejor lo dejamos para otro día. Si mientras tanto queréis echar un ojo, en la página de varnish hay unos cuantos ejemplos de ficheros VCL y un manual de uso de VCL.

Una vez reiniciado los servicios deberíamos tenerlos levantados en sus correspondientes puertos:

root@testvarnish:~# netstat -lnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:6082 0.0.0.0:* LISTEN 2623/varnishd 
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 2625/varnishd 
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1570/sshd 
tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN 6527/apache2

 

Comprobando el rendimiento

Para ver si nuestro sistema de cache se comporta correctamente podemos ejecutar la instrucción varnishstat que nos permitirá ver en tiempo real muchos datos relativos al rendimiento y el estado de los servicios.

Entre otros, los más interesantes pueden ser:

  • La cantidad de sesiones aceptadas (client_conn)
  • Los aciertos y fallos en cache (cache_hit / cache_miss)
  • Los fallos detectados en los servidores web (backend_fail)
  • El número de hilos activos (n_wrk).

2 Comments

  • Alexander Torres |

    Estoy teniendo problemas en la instalacion de varnish, me gustaria un tutorial completo ya que tengo un servuidor que reparte dhcp, tiene filtrado con squid en el puerto 3128.

    Sigo las instrucciones puestas en esta pagina pero al momento de realizar el cacheado no me parece nada en varnishhit.

    Me aparecen todos los valores en 0.

    Agradezco si me puede ayudar con el tema. con un manual mas completo con referente a la esctructura que tengo de red.
    saludos cordiales.

    • Manuel Gracia |

      Hola Alexander.
      En principio no debería haber problemas de incompatibilidad entre los programas que comentas, así que la guía tal cual debería ser válida.

      Si se me ocurre que, si squid está funcionando en modo transparente, podría haber algún problema con las reglas de firewall que redireccionan el tráfico del puerto 80 al 3128.
      ¿Podría asegurar mediante un “iptables-save” que no hay ninguna regla que redireccione el tráfico dirigido al puerto 80 del propio servidor?

      También debería asegurar que la aplicación se está ejecutando en el puerto correcto. Si ejecuta “netstat -lnp” como root debería aparecer varnish escuchando en el puerto :80 y el servidor web en el puerto :8888 (o el que haya configurado).

      La página web que intenta mostrar, ¿se ve correctamente?. Si ve en los encabezados html, dentro de la respuesta del servidor, un “Via: varnish” es que la información está siendo procesada por varnish.

      Un saludo.