Tutorial básico de Varnish



Qué es y para qué sirve Varnish

Varnish es un proxy HTTP inverso de alto rendimiento, también llamado "acelerador HTTP".

Su función es la de recibir peticiones HTTP, solicitarlas al servidor Web real, y cachear los contenidos HTTP devueltos (imágenes, vídeos, la salida de la ejecución de scripts PHP, etc) en su caché interna para futuras peticiones. Las siguientes peticiones del mismo recurso serán servidas desde la caché, evitando llamadas al servidor HTTP real durante el tiempo que queramos que sean cacheadas.

Debido a que sirve (durante un tiempo) versiones cacheadas de los contenidos en lugar de volver a solicitar la ejecución de los contenidos dinámicos, se reduce el tiempo necesario para servir la página y se eliminan accesos al servidor web real y también al servidor de base de datos utilizado por el servidor Web para generar la página.

La configuración básica de Varnish (con un sólo servidor) es ubicar nuestro actual servidor Web (NGINX, Apache, etc) al puerto 81 (convirtiéndolo en lo que Varnish llama un "backend HTTP"), y levantar Varnish en el puerto 80 atendiendo las peticiones HTTP de los usuarios ("clientes HTTP").



Cuando Varnish recibe las peticiones HTTP, podrá decidir entre:


  • Aceptarlas o denegarlas en base a determinados criterios.
  • Pasarlas directamente al backend HTTP para que las atienda y devuelva a Varnish la salida de la petición.
  • Cachear (según determinados criterios que impongamos) la salida devuelta por el backend HTTP a una determinada petición bien a memoria o a disco.
  • Servir la respuesta desde la caché (según determinados criterios que impongamos) en lugar de pasarla al backend.


En todo este proceso, Varnish podrá además manipular las cabeceras HTTP de las respuestas, imponiendo "TTLs", tiempos de expiración, eliminando cabeceras, Cookies, etc, según las reglas de configuración que le hayamos indicado.

El resultado es que Varnish podrá servir contenidos estáticos y dinámicos sin que estas peticiones lleguen realmente al backend HTTP, lo que puede producir un increible incremento de rendimiento en nuestra plataforma Web.

La configuración es suficientemente flexible como para poder decidir durante cuánto tiempo cachear los contenidos estáticos, los contenidos dinámicos, definir a qué contenidos aplicamos las reglas por la extensión del fichero en cuestión, por matcheo de expresiones regulares en el host o la URL, etc.

Esto puede permitir cachear los contenidos estáticos (por subdominio de estáticos o por extensión del fichero) durante mucho tiempo y los dinámicos (por ejemplo, la salida de ejecutar un PHP) durante un tiempo menor, digamos de 1 segundo, haciendo un microcacheo imperceptible para los usuarios pero que permite llegar sólo 1 petición por URL por segundo al backend HTTP. Además podremos excluír del cacheo aquellas URLs que necesiten ser accedidas en tiempo real y no permitan cacheo.

Por otra parte, Varnish también puede colocarse delante de varios servidores HTTP de forma que permita:


  • Balancear peticiones entre varios servidores HTTP, pudiendo asignar pesos a los mismos.
  • Enviar peticiones de unos subdominios o extensiones (según regexp contra Host: o URL:, por ejemplo) a unos servidores u otros.


El uso de Varnish es normalmente un salto cualitativo en el tiempo de respuesta y rendimiento de plataformas Web.



Instalando y arrancando Varnish


Instalación de Varnish

Varnish está disponible por defecto en cualquier distribución Linux moderna, por lo que bastará con ejecutar:


  • Distribuciones basadas en APT (via repositorio estándar): apt-get install varnish
  • Distribuciones badadas en YUM (via repositorio EPEL): yum install varnish.


También hay disponibles repositorios PPA (APT) para Varnish y para YUM:



Por ejemplo:

### CentOS 5 (paquetes compatibles con CentOS 6)

# rpm --nosignature -i \
  http://repo.varnish-cache.org/redhat/varnish-3.0/el5/noarch/varnish-release-3.0-1.noarch.rpm
# yum install varnish


Parámetros de arranque de Varnish

Los parámetros de arranque de Varnish están ubicados en:

  • RPM → /etc/sysconfig/varnish
  • DEB → /etc/default/varnish

Por ejemplo, el fichero /etc/default/varnish en Debian / Ubuntu (con comentarios):

# cat /etc/default/varnish

# Configuration file for varnish
#
# /etc/init.d/varnish expects the variables $DAEMON_OPTS, $NFILES and $MEMLOCK
# to be set from this shell script fragment.
#

# Should we start varnishd at boot?  Set to "yes" to enable.
START=yes

# Maximum number of open files (for ulimit -n)
NFILES=131072

# Maximum locked memory size (for ulimit -l)
# Used for locking the shared memory log in memory.  If you increase log size,
# you need to increase this number as well
MEMLOCK=82000

# Default varnish instance name is the local nodename.  Can be overridden with
# the -n switch, to have more instances on a single server.
INSTANCE=$(uname -n)

# This file contains 4 alternatives, please use only one.

## Alternative 1, Minimal configuration, no VCL
#
# Listen on port 6081, administration on localhost:6082, and forward to
# content server on localhost:8080.  Use a 1GB fixed-size cache file.
#
# DAEMON_OPTS="-a :6081 \
#              -T localhost:6082 \
# 	     -b localhost:8080 \
# 	     -u varnish -g varnish \
#            -S /etc/varnish/secret \
# 	     -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G"


## Alternative 2, Configuration with VCL
#
# Listen on port 6081, administration on localhost:6082, and forward to
# one content server selected by the vcl file, based on the request.  Use a 1GB
# fixed-size cache file.
#
DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G"

## Alternative 3, Advanced configuration
#
# See varnishd(1) for more information.
#
# # Main configuration file. You probably want to change it :)
# VARNISH_VCL_CONF=/etc/varnish/default.vcl
#
# # Default address and port to bind to
# # Blank address means all IPv4 and IPv6 interfaces, otherwise specify
# # a host name, an IPv4 dotted quad, or an IPv6 address in brackets.
# VARNISH_LISTEN_ADDRESS=
# VARNISH_LISTEN_PORT=6081
#
# # Telnet admin interface listen address and port
# VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
# VARNISH_ADMIN_LISTEN_PORT=6082
#
# # The minimum number of worker threads to start
# VARNISH_MIN_THREADS=1
#
# # The Maximum number of worker threads to start
# VARNISH_MAX_THREADS=1000
#
# # Idle timeout for worker threads
# VARNISH_THREAD_TIMEOUT=120
#
# # Cache file location
# VARNISH_STORAGE_FILE=/var/lib/varnish/$INSTANCE/varnish_storage.bin
#
# # Cache file size: in bytes, optionally using k / M / G / T suffix,
# # or in percentage of available disk space using the % suffix.
# VARNISH_STORAGE_SIZE=1G
#
# # File containing administration secret
# VARNISH_SECRET_FILE=/etc/varnish/secret
# 
# # Backend storage specification
# VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}"
#
# # Default TTL used when the backend does not specify one
# VARNISH_TTL=120
#
# # DAEMON_OPTS is used by the init script.  If you add or remove options, make
# # sure you update this section, too.
# DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
#              -f ${VARNISH_VCL_CONF} \
#              -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
#              -t ${VARNISH_TTL} \
#              -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \
# 	       -S ${VARNISH_SECRET_FILE} \
#              -s ${VARNISH_STORAGE}"
#

## Alternative 4, Do It Yourself
#
# DAEMON_OPTS=""

Y /etc/sysconfig/varnish en RedHat / CentOS (sin comentarios, ya que los parámetros de arranque son iguales que en Debian):

# cat /etc/sysconfig/varnish
NFILES=131072
MEMLOCK=82000
VARNISH_VCL_CONF=/etc/varnish/default.vcl
VARNISH_PORT=80
VARNISH_LISTEN_ADDRESS=""
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
VARNISH_MIN_THREADS=200
VARNISH_MAX_THREADS=2000
VARNISH_THREAD_TIMEOUT=120
VARNISH_STORAGE_FILE=/cache/varnish/varnish_storage.bin
#VARNISH_STORAGE_SIZE=50%
VARNISH_STORAGE_SIZE=60G
VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}"
VARNISH_TTL=120

DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_PORT} \
             -f ${VARNISH_VCL_CONF} \
             -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
             -t ${VARNISH_TTL} \
             -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \
             -u varnish -g varnish \
             -s ${VARNISH_STORAGE} \
             -p thread_pool_min=200 \
             -p thread_pool_max=2000 \
             -p thread_pools=8 \
             -p listen_depth=4096 \
             -p session_linger=50/100/150 \
             -p lru_interval=60"

Los parámetros de arranque son bastante intuitivos, y pueden ser modificados directamente en DAEMON_OPTS o bien en las variables "genéricas" de los ficheros.

Los más destacables son:


  • -a IP_DONDE_ESCUCHAR:PUERTO → Indica la IP y puerto donde poner escuchará Varnish para atender peticiones HTTP. Indicar ":PUERTO" para que escuche en todas las IPs.
  • -T IP_DONDE_ESCUCHAR:PUERTO → Indica dónde escuchará la interfaz de administración de Varnish.
  • -t TTL → TTL por defecto para usar para los contenidos cuando el backend no especifique uno.
  • -p thread_ y -w valores → Configuración de threads de ejecución (ajustar según carga, memoria, etc).
  • -s STORAGE → Indica si queremos cachear a memoria o a disco, así como dónde y cuánto:
    • A memoria (absoluto)→ -s malloc,2G (cachear en 2GB de memoria).
    • A disco (absoluto) → -s file,/cache/varnish/varnish_storage.bin,60G (cachear en 60GB de disco en el path indicado).
    • A disco (relativo) → -s file,/cache/varnish/varnish_storage.bin,50% (cachear en el path indicado, ocupando máximo el 50% del espacio).
  • -f path_configuracion → Ruta al fichero de configuración a utilizar.


El resto de parámetros de configuración, así como la definición de qué debe de hacer varnish según cabeceras de entrada, de salida y URLs solicitadas por los clientes, se especifican en el fichero de configuración /etc/varnish/default.vcl o en su defecto el que indiquemos con el flag de arranque -f.

El cacheo a memoria es, en teoría, mucho más rápido que el cacheo a disco, pero nos encontramos con la limitación de la cantidad de memoria disponible y que tenemos que compartir ésta con NGINX o Apache, y con el propio host. En muchas ocasiones puede resultar más útil cachear a disco local y dejar la memoria disponible para "varnishd" (no para su caché) y para el resto de servicios del servidor. Además, normalmente la caché de disco podrá de ser mucho mayor tamaño que la de memoria.

Si cacheamos a disco, se recomienda montar la partición de caché con las opciones noatime y nodiratime. En determinadas plataformas que requieran mucho rendimiento, también podemos montar el directorio de trabajo de Varnish (normalmente /var/lib/varnish o /usr/lib/varnish) en un filesystem tmpfs. Es importante destacar también que algunos "paquetes" de varnish ubican el storage en el mismo path que el shmlog, algo que querremos evitar por cuestiones de rendimiento.

Una vez instalado varnish, podemos arrancarlo/pararlo/recargar la configuración con los scripts de /etc/init.d (APT) o con service (RPM):

# service varnish start
# service varnish stop
# service varnish restart
# service varnish reload

Para realizar acciones o cambios de configuración en un varnish en ejecución podemos realizar un telnet al puerto administrativo o bien utilizar el binario varnishadm con sus diferentes subcomandos: vlc.load, vlc.use, param.show, param.set, etc.



VCL: Varnish Configuration Language

En contraposición a otros sistemas basados en directivas ON/OFF, Varnish se configura mediante un lenguaje propio de "lógica de gestión de las peticiones" que es compilado en código binario y que se ejecuta cuando llegan las peticiones HTTP.

Además, la configuración de Varnish permite embeber código C dentro de la lógica de gestión de las peticiones, ya que la configuración de Varnish es traducida a C y es éste código C el que se compila y ejecuta, lo que impone como dependencia a "gcc" en el sistema a la hora de instalar Varnish.

El "lenguaje" de configuración de Varnish se llama VCL (Varnish Configuration Language). En este lenguaje debemos definir una serie concreta de "subrutinas" y código dentro de las mismas. Varnish llamará a cada una de estas subrutinas en algún punto del procesado de la petición.

Este lenguaje soporta estructuras "tipo C" como if, include, comentarios de como //, /* */ y #, salida de funciones con return(), asignaciones con =, comparaciones con ==, negación con !, and y or lógico con && y ||, matcheo contra expresiones regulares con ~ y establecer/eliminar atributos con set y unset. También tenemos funciones como regsub y regsuball (sustitución por expresiones regulares de una o todas las ocurrencias).

En un posterior ejemplo veremos que la sintaxis de este lenguaje y su uso es muy intuitivo.

Para lo que es la estructura del "programa", en VCL nos ceñimos a una serie de subrutinas concretas ya existentes (tienen ya un código "por defecto") cuyo "contenido" podemos redefinir para que el flujo de atención y procesado de las peticiones sea exáctamente el deseado por nosotros. Las rutinas en cuestión son: vlc_recv(), vcl_fetch(), vcl_pass(), vcl_hit(), vcl_miss(), vcl_deliver(), vcl_error(), vcl_pipe() y vcl_hash() (principalmente).

Cuando una petición HTTP llega a Varnish, éste la procesa llamando a las diferentes rutinas en un orden concreto, y se ejecuta el código que hay dentro de dichas subrutinas. Ese código puede ser el código por defecto de Varnish o bien código personalizado por nosotros. Existe un órden concreto de ejecución de las subrutinas, como veremos más adelante.

De todas estas rutinas, hay 2 que serán las que contendrán el 95% del código propio que utilizaremos en nuestra Web. Las rutinas principales cuyo código modificaremos para alterar el funcionamiento de Varnish durante el procesado de una petición y a las que nos referimos son:


  • vcl_recv() → Varnish llama a esta subrutina cuando se recibe una petición HTTP y Varnish la ha procesado y parseado. Dentro de esta subrutina decidiremos si aceptamos o no la petición, cómo hacerlo y usando qué backend HTTP. Estas decisiones las tomaremos en función del contenido del objeto req (request), que es rellenado por varnish al atender la petición y contiene todos los datos sobre la petición (req.host, req.url, etc).
  • vcl_fetch() → Varnish llama a esta subrutina después de haber obtenido del backend HTTP con éxito los datos solicitados por Varnish, después de haberse aceptado la petición en vlc_recv(). Dentro de esta subrutina seguimos disponiendo del objeto req, y además tenemos el nuevo objeto beresp (backend response), que contiene más datos manipulables por nosotros para alterar la respuesta (eliminar cookies, cambiar el TTL, etc). En esta subrutina normalmente se puede alterar la respuesta del backend, se puede atacar a backends alternativos en caso de no obtener respuesta, etc.


Dentro de estas 2 funciones (y de otras que veremos a continuación) podemos realizar diferentes acciones, que suelen consistir en devolver a Varnish el control indicándole cómo queremos continuar el flujo de atención de la petición. Para devolver el control a varnish utilizaremos con "return()" diferentes "códigos de retorno" que provocarán resultados o efectos concretos según el código devuelto:


  • pass → Si para la petición HTTP en curso devolvemos pass (con return(pass);), la petición se envía al servidor Backend HTTP sin buscarse en la caché y la respuesta del backend HTTP se devuelve al cliente sin cachearse. Esta respuesta puede darse en vcl_recv() en función de si se cumplen o no determinados criterios que nosotros consideremos. No podemos devolver un pass desde vcl_fetch(). Con "pass" le indicamos pues a Varnish que queremos devolver la respuesta del servidor HTTP sin cachearla ni buscarla en caché. Se recomienda establecer un valor para beresp.ttl cuando se hace un pass en vcl_fetch(), así como realizar los pass en vcl_recv (paso inicial del procesado) si es posible en lugar de hacer pass o hit_for_pass en vcl_fetch().
  • pipe → Esta acción "cortocircuita" el cliente HTTP y el Backend HTTP de forma que Varnish se limita a transferir datos de uno a otro. Es similar a pass (no se cachea) y además Varnish no se dedica a inspeccionar el tráfico HTTP ni rellenar los objetos req/beresp/obj por lo que a veces se utiliza para evitar que objetos muy grandes (vídeos, etc) sean "procesados" por varnish. También se utiliza para que el cliente HTTP hable directamente con el Backend HTTP para métodos HTTP no soportados por Varnish. Con "pipe" le indicamos a Varnish que queremos comunicar Cliente HTTP con Backend HTTP y que Varnish haga sólo de intermediario del flujo de datos, sin procesarlos.
  • lookup → Cuando se devuelve return(lookup); desde vcl_recv(), lo que hacemos es forzar a que Varnish devuelva el objeto desde la caché incluso si la petición en sí misma está solicitando contenido no cacheado. No se puede devolver este valor desde vcl_fetch(), porque en vcl_fetch() ya hemos obtenido el dato desde el Backend HTTP. Con "lookup" le indicamos a Varnish que queremos usar la caché para atender esta petición.
  • deliver → Devolver el dato cacheado al cliente HTTP (normalmente devuelto desde vcl_fetch()). Le indica a Varnish que queremos devolver al cliente HTTP el dato cacheado, si es posible.
  • hit_for_pass → (No lo utilizaremos en este tutorial básico) Similar a pass (pero accesible desde vcl_fetch) salvo porque crea un objeto de tipo hitforpass y lo que se hace en este caso es cachear la decisión de no cachear. La utilidad de esto es la siguiente: supongamos que Varnish solicita un dato al backend y se encuentra con que ese dato no es cacheable. En ese caso, Varnish crea un objeto en la caché que "almacena" (durante la duración del ttl por defecto) la decisión de que ese objeto no es cacheable, de forma que las siguientes peticiones irán directamente a "pass". Realizar un hit_for_pass, además de no cachear, no ejecuta vcl_pass(): será la próxima petición del mismo recurso la que lo realizará. Hay que tener cuidado porque esto puede implicar el cachear durante el ttl indicado tanto la respuesta del backend como la decisión sobre el cacheo. Esto podría implicar, por ejemplo, cachear un error 500 devuelto por el backend HTTP. Por eso, es mejor hacer "pass" en vcl_recv() siempre que sea posible.
  • restart → Ofrece una forma de volver a ejecutar la lógica de VCL desde el principio, tras incrementar la variable req.restarts (hasta un máximo de max_restarts). Puede permitir, por ejemplo, reescribir el host o la URL y "reejecutar" la petición. Este restart se produce volviendo a procesar la petición desde el principio de vcl_recv(), pero manteniendo todos los cambios realizados en el objeto req por la anterior lógica.


Además de vcl_fetch() y vcl_recv() existen también otras funciones que en configuraciones de mayor nivel podemos necesitar alterar:


  • vcl_hash() → Permite alterar el hash que se utiliza para gestionar el objeto en la caché. Normalmente es la URL pero podemos alterar dicho hash a nuestra voluntad. Un ejemplo sería cachear la página del perfil (/profile/) de cada usuario, añadiendo concatenando la cookie de usuario a la URL, lo que generaría un objeto distinto en cada para cada usuario.
  • vcl_pipe() → Es llamada al entrar en "modo pipe".
  • vcl_pass() → Es llamada al entrar en "modo pass". En ella (además de hacer un pass) podemos forzar a que se reinicie la transacción, lo cual incrementa un contador interno de "restart" que podemos detectar en otras funciones.
  • vcl_hit() → Es llamada cuando un lookup en la caché encuentra un objeto válido en ella. Aquí podemos hacer deliver, pass o restart.
  • vcl_miss() → Es llamada cuando un lookup en la caché no encuentra un objeto válido. Nos permite tomar decisiones de si probar algún backend alternativo, por ejemplo. Podemos devolver fetch (solicitar el objeto al backend) o pass.
  • vcl_error() → Es llamada cuando se encuentra un error por cualquier motivo (interno, porque ha sido lanzado manualmente desde una subrutina vía código VCL, etc.
  • vcl_deliver() → Es llamada antes de que un objeto cacheado sea entregado al cliente HTTP.


En la página de Varnish podemos encontrar el enlace a un diagrama con la lógica VCL. A continuación se reproduce una versión "reducida" del mismo creada por el usuario perbu de nombre "VCL Graph":



Este diagrama muestra el flujo de llamadas de las funciones vcl_*() desde que la petición entra (parte superior) hasta que se entrega al cliente HTTP (parte inferior) según las acciones (return(acción)) que vayamos tomando en ellas.

Nuestra función como administradores de Varnish es escribir un fichero de configuración VCL que defina cómo queremos que se comporte Varnish en cada una de estas funciones, considerando todas las posibilidades para los objetos que entran: cuáles queremos cachear, cuáles deben de ser servidos sin cachear, etc. Esto lo haremos en base a reglas de matcheo (if / == / ~) contra la cabecera Host:, contra la URL, contra cabeceras de la petición o devueltas por el backend HTTP, etc.

Las funciones vcl_* que no "definamos" en nuestro VCL serán consideradas "vacías" y para ellas se ejecutará el código "por defecto" de Varnish asociado a esa función (también ocurrirá lo mismo si abandonamos una función sin haber hecho un return en ella). Posteriormente veremos cuál es el código por defecto de Varnish para cada una de las funciones vcl_*.



Ejemplo: cacheo de imágenes estáticas de /images/

Veamos un ejemplo de fichero VCL básico, que consta de:


  • La definición del backend HTTP que vamos a usar (apache escuchando en localhost:81).
  • Una rutina vcl_recv() que tratará de devolver desde la caché cualquier petición cuya URL contenga la cadena ^/images/, y que devolverá sin cachear (directamente desde el Apache) el resto de URLs.
  • Una rutina vcl_fetch() que cacheará las peticiones cuya URL contenga ^/images/ y además alterará el TTL de la respuesta para que sea cacheado 7 días.


#---------------------------------------------------------------------
# Definimos para Varnish un backend HTTP (apache en 127.0.0.1:81)
#---------------------------------------------------------------------
backend apache 
{
  .host = "127.0.0.1";
  .port = "81";
  #.connect_timeout = 600s;
  #.first_byte_timeout = 600s;
  #.between_bytes_timeout = 600s;
  #.max_connections = 100;
}
 

#---------------------------------------------------------------------
# Una ACL para identificar a los desarrolladores web (sin cacheo)
#---------------------------------------------------------------------
acl desarrolladores 
{
   "localhost";
   "10.0.0.0"/8;
   "192.168.1.0"/24;
   ! "192.168.1.1";                    // Excluimos la IP del router
   // include "lista_ips.txt";
   // ("midominio.com"/24);
   // !"host.excluido.com";
   // "host.incluido.com";
}

#---------------------------------------------------------------------
# vcl_recv()
#
# Esta funcion sera llamada cada vez que llegue una peticion HTTP
# En ella normalmente devolveremos pass, lookup o pipe.
#
# Trabajaremos en ella con el objeto req (request), que tiene varios
# atributos tanto de lectura como de escritura.
#---------------------------------------------------------------------
sub vcl_recv 
{

    # Especificamos el backend por defecto para esta peticion:
    set req.backend = apache;
 
    # Los desarrolladores no quieren cacheo:
    if (client.ip ~ desarrolladores)
    {
        return(pass);
    }
    
    # Eliminamos de la peticion HTTP el requerimiento del cliente
    # de usar gzip / deflate / etc (varnish 2.x no lo soporta).
    unset req.http.Accept-Encoding;
 
    # Si la URL de la peticion contiene la regexp ^/images/, tratar
    # de devolverla desde la cache de varnish:
    if (req.url ~ "^/images/") 
    {
        # Eliminamos primero las cookies que nos pueda mandar el cliente
        unset req.http.cookie;
        return(lookup);
    }
 
    # Si hemos llegado aqui, es que la peticion no es de ^/images/, 
    # asi que la pasamos directamente del backend sin cachear
    return(pass);
}
 
 
#---------------------------------------------------------------------
# vcl_fetch()
#
# Esta funcion sera llamada cada vez que se recoge la salida de una
# peticion HTTP desde el backend HTTP.
#
# Trabajaremos en ella con el objeto beresp (backend response), que
# tiene varios atributos tanto de lectura como de escritura.
#
# En ella devolveremos normalmente pass o deliver.
#---------------------------------------------------------------------
sub vcl_fetch 
{
    
    if (req.url ~ "^/images/") 
    {
        # Eliminamos las cookies que pueda devolver el backend HTTP
        unset beresp.http.Set-Cookie;
 
        # Indicamos que se cachee durante 7 dias:
        set beresp.ttl = 7d;
        
        return(deliver);
    }
    
    # Al no indicar aqui ningun return, en las peticiones que no matchean
    # con ^/images/ se continuara con la ejecución de la funcion
    # vcl_fetch() por defecto de varnish.
}

Podemos introducir el anterior ejemplo en el fichero /etc/varnish/default.vcl" o bien crearlo como /etc/varnish/cachear_images.vcl, comentar todo el fichero default.vcl y poner al principio de mismo:

include "/etc/varnish/cachear_images.vcl";

Nótese que a la hora de trabajar con objetos cacheados, uno de los parámetros más importantes es "beresp.ttl", el tiempo que queremos que Varnish mantenga ese objeto en la caché, y que modificamos en vlc_fetch.

En otras funciones (vcl_hit) podemos modificar obj.ttl, referente a ese objeto de caché en cuestión, por ejemplo, para hacerlo expirar (haciendo obj.ttl = 0).


Cómo validar la configuración de Varnish

Si introducimos un error en la configuración de Varnish y tratamos de hacer un reload o restart del servicio, nos encontraremos con que la compilación del fichero .vcl fallará y tendremos el servicio caído y un fichero de configuración con errores.

Para evitar esta situación, podemos chequear la sintaxis del fichero de configuración antes de hacer el reload/restart. Varnish no tiene un equivalente al "apachectl configtest" de Apache, pero sí que podemos hacer uso en Varnish 2 y 3 de la función -C, que compila el fichero VCL y muestra el resultado de la compilación por la salida estándar (stdout):

# varnishd -C -f /etc/varnish/default.vcl

Si todo es correcto, varnish mostrará la configuración "compilada". Si no, se nos presentaré el mensaje de error informativo sobre la línea específica que contiene el error. El mismo mensaje que aparecería si hiciéramos un reload/restart, pero con el servicio todavía en ejecución.

Así, podemos corregirlo, volver a testear la configuración, y de esta forma hacer un reload/restart con la seguridad de que no va fallar.



Lógica VCL por defecto de varnish

Como ya hemos comentado anteriormente, si no definimos código para una función vcl_() específica, se ejecuta la lógica por defecto de Varnish para esa subrutina.

Y como se se puede leer en el último comentario del código del ejemplo anterior, cuando creamos nuestra propia configuración y escribimos nuestra propia versión de las funciones VCL, si la lógica de las mismas finaliza sin haber realizado un pass, lookup, error, restart o pipe, Varnish también continuará la función en cuestión ejecutando la lógica por defecto que tiene programada.

De hecho, podemos tener múltiples definiciones de una misma función vcl_fetch (por ejemplo) en varios ficheros .vcl (y hacer varios include "fichero.vcl"; de ellos), y en ese caso serán llamadas todas las subrutinas vcl_fetch() existentes en el orden en que han sido incluídas, acabando la ejecución en la función de lógica por defecto de Varnish.

Estas funciones "por defecto" (que aparecen en el diagrama como "default") son las que se pueden ver (comentadas) en el fichero /etc/varnish/default.vcl:

# Default backend definition.  Set this to point to your content server.

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

# Default VCL logic.  If you redefine any of these subroutines, the
# built-in logic will be appended to your code.

sub vcl_recv {

    # Establecer cabecera X-Forwarded-For para el backend:
    if (req.restarts == 0) {
	if (req.http.x-forwarded-for) {
	    set req.http.X-Forwarded-For =
		req.http.X-Forwarded-For ", " client.ip;
	} else {
	    set req.http.X-Forwarded-For = client.ip;
	}
    }
    
    /* Bypassear al backend peticiones que Varnish no entiende */
    if (req.request != "GET" &&
      req.request != "HEAD" &&
      req.request != "PUT" &&
      req.request != "POST" &&
      req.request != "TRACE" &&
      req.request != "OPTIONS" &&
      req.request != "DELETE") {
        /* Non-RFC2616 or CONNECT which is weird. */
        return (pipe);
    }
    
    if (req.request != "GET" && req.request != "HEAD") {
        /* We only deal with GET and HEAD by default */
        return (pass);
    }
    
    # Varnish no maneja ni la autenticación ni las cookies -> pass
    if (req.http.Authorization || req.http.Cookie) {
        /* Not cacheable by default */
        return (pass);
    }
    return (lookup);
}

sub vcl_pipe {
    # Note that only the first request to the backend will have
    # X-Forwarded-For set.  If you use X-Forwarded-For and want to
    # have it set for all requests, make sure to have:
    # set bereq.http.connection = "close";
    # here.  It is not set by default as it might break some broken web
    # applications, like IIS with NTLM authentication.
    return (pipe);
}

sub vcl_pass {
    return (pass);
}

sub vcl_hash {
    set req.hash += req.url;
    if (req.http.host) {
        set req.hash += req.http.host;
    } else {
        set req.hash += server.ip;
    }
    return (hash);
}

sub vcl_hit {
    if (!obj.cacheable) {
        return (pass);
    }
    return (deliver);
}

sub vcl_miss {
    return (fetch);
}

sub vcl_fetch {
    if (!beresp.cacheable) {
        return (pass);
    }
    if (beresp.http.Set-Cookie) {
        return (pass);
    }
    return (deliver);
}

sub vcl_deliver {
    return (deliver);
}

sub vcl_error {
    set obj.http.Content-Type = "text/html; charset=utf-8";
    synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>"} obj.status " " obj.response {"</title>
  </head>
  <body>
    <h1>Error "} obj.status " " obj.response {"</h1>
    <p>"} obj.response {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} req.xid {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"};
    return (deliver);
}

A la hora de reescribir las funciones vcl_* con nuestro propio código, debemos de tener en cuenta que las funciones por defecto se ejecutarán si salimos de nuestras versiones propias sin realizar ninguna acción. También se ejecutará la función por defecto si no reescribimos alguna de estas funciones, ya que puede darse el caso que sólo queramos modificar alguna de ellas y no es obligatorio reescribir todo el set.

Por ejemplo, podemos reescribir vcl_error para mostrar un mensaje de error más acorde al aspecto de nuestra Web, o bien no definir esa función con lo que se generaría la salida del vcl_error() por defecto.



Logs y estadísticas

A la hora de obtener datos sobre el funcionamiento de varnish tenemos que tener presentes 2 binarios incluídos con él: varnishlog y varnishstat.


Varnishlog : logs en tiempo real

Varnish no guarda su log en disco, como lo hacen Apache y NGINX. En lugar de esto, almacena los logs en un segmento de memoria compartida. Cuando el segmento de memoria compartida se llena, se reutiliza sobreescribiendo los datos antiguos (este procedimiento es mucho más rápido que logar a disco).

Así pues, no podemos ver los logs de Varnish con less o tail. Para eso se utiliza el binario varnishlog.

varnishlog visualiza en tiempo real los logs de una instancia de varnishd en ejecución (generados en memoria), similar a si hicieramos un "tail -f" de un fichero de log (pero sin estar presente en disco).

Con ciertos flags de arranque (-w, -a, -D) podemos generar el log a disco y ejecutar el binario en modo daemon, aunque normalmente no es necesario salvo en las depuraciones iniciales o en estudios para aumentar el ratio de hits en caché. Permite incluír o excluir (flags -m, -i, -x, -X) entradas de log que queremos o no queremos ver en base a tags o expresiones regulares. Todos los parámetros y tags utilizables están definidos en su página man (man varnishlog).

Este es el aspecto de los logs de varnish en "varnishlog" durante la petición de un fichero PNG a un servidor web detrás de Varnish:

   14 SessionOpen  c 127.0.0.1 59005 :80
   14 ReqStart     c 127.0.0.1 59005 1322431649
   14 RxRequest    c GET
   14 RxURL        c /images/adv_background/microads_135779047.png
   14 RxProtocol   c HTTP/1.1
   14 RxHeader     c Host: static.dominio.es
   14 RxHeader     c User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:12.0)
                     Gecko/20100101 Firefox/12.0
   14 RxHeader     c Accept: text/html,application/xhtml+xml;q=0.9,*/*;q=0.8
   14 RxHeader     c Accept-Language: es,en-us;q=0.7,en;q=0.3
   14 RxHeader     c Accept-Encoding: gzip, deflate
   14 RxHeader     c Connection: keep-alive
   14 RxHeader     c Cookie: preferred_site=es; __utma=1689.2710.1396.14762.14919.5; 
                     __utmz=16892.1336.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);
                     __utmv=16832.ir00_lang8_m0_gm_p0; rsi_segs=L10140_1005;
   14 RxHeader     c Cache-Control: max-age=0
   14 VCL_call     c recv lookup
   14 VCL_call     c hash
   14 Hash         c /images/adv_background/microads_135779047.png
   14 Hash         c static.dominio.es
   14 VCL_return   c hash
   14 Hit          c 1322431598
   14 VCL_call     c hit deliver
   14 VCL_call     c deliver deliver
   14 TxProtocol   c HTTP/1.1
   14 TxStatus     c 200
   14 TxResponse   c OK
   14 TxHeader     c Server: nginx
   14 TxHeader     c Content-Type: image/png
   14 TxHeader     c Last-Modified: Mon, 30 Apr 2012 09:44:07 GMT
   14 TxHeader     c Expires: Mon, 07 May 2012 16:55:16 GMT
   14 TxHeader     c cache-control: max-age = 1296000
   14 TxHeader     c Content-Length: 363163
   14 TxHeader     c Accept-Ranges: bytes
   14 TxHeader     c Date: Mon, 30 Apr 2012 16:56:01 GMT
   14 TxHeader     c X-Varnish: 1322431649 1322431598
   14 TxHeader     c Age: 45
   14 TxHeader     c Via: 1.1 varnish
   14 TxHeader     c Connection: keep-alive
   14 Length       c 363163
   14 ReqEnd       c 1322431649 1335804961.828757524 1335804961.829684496 
                     0.000100136 0.000106573 0.000820398

(Si no estamos recibiendo visitas, sólo veremos líneas de ping y respuestas PONG, que utiliza Varnish internamente para chequear que todo funciona correctamente).


  • El primer valor de cada línea es un identificador de la transacción: las líneas con un mismo identificador pertenecen a una misma petición HTTP.
  • La segunda columna es el tag del mensaje; esto nos permite saber a qué tipo de operación se refiere cada línea. Los tags que empiezan por Rx se refieren a que Varnish recibe un dato y los que empiezan por Tx a que lo transmite.
  • La tercera columna nos dice si el origen o destino es el cliente © o el backend (b).
  • Finalmente, la última columna es el dato en cuestión a logar.


Nótese que la última línea de cada petición, el ReqEnd, nos proporciona información sobre los tiempos de respuesta:


  • El primer número es el XID (identificador que podemos encontrar en la cabecera X-Varnish enviada al cliente HTTP).
  • El segundo número es el tiempo EPOCH cuando Varnish comenzó a procesar la petición.
  • El tercer número es el tiempo EPOCH cuando Varnish finalizó la petición.
  • El cuarto número es el tiempo transcurrido entre que la petición fue aceptada y el inicio del procesado.
  • El quinto número es el tiempo transcurrido entre el inicio del procesado de la petición y el inicio de la entrega del objeto al cliente HTTP (a efectos prácticos, el tiempo de respuesta del backend).
  • El sexto número es el tiempo desde que Varnish comenzó a entregar el objeto al cliente HTTP, hasta que finaliza la transacción completa.


A la hora de ejecutar Varnish, como hemos visto tenemos flags disponibles que nos ayudan a filtrar lo que queremos ver. Los flags que más utilizaremos son:


  • -b → Mostrar sólo las líneas de tráfico entre Varnish y el Backend HTTP.
  • -c → Mostrar sólo las líneas de tráfico entre Varnish y el Cliente HTTP.
  • -m tag:regexp → Mostrar sólo las transacciones donde el tag cumpla una expresión regular. Si se produce match, se muestra la transacción completa.


En la página oficial de Varnish tenemos los siguientes ejemplos de uso de varnishlog:

# Ver logs completos:
varnishlog

# Ver solo peticiones POST:
varnishlog -c -o RxRequest POST 

# Ver sólo las peticiones generadas por la IP de un cliente concreto:
varnishlog -c -m ReqStart:1.2.3.4

# Ver sólo las peticiones a backend generadas por la IP de un cliente
# gracias a que dicha IP aparece en la cabecera X-Forwarded-For:
varnishlog -c -m TxHeader:1.2.3.4

# Ver solo los tags ReqEnd, para poder detectar peticiones "lentas":
varnishlog -O -i ReqEnd

# Ver solo las URLs enviadas al backend HTTP (cache miss y pass):
varnishlog -O -i TxURL

# Ver solo las peticiones que incluyan una URL concreta:
varnishlog -c -m RxURL:/path/url/

# Ver solo la cadena de User-Agent:
varnishlog -c -i RxHeader -I User-Agent 

# Ver solo la cadena de Accept-Encoding:
varnishlog -c -i RxHeader -I Accept-Encoding 

# Ver solo las respuestas del backend del tipo POST:
varnishlog -b -m TxRequest:POST

# Logar solo peticiones donde Varnish permita al navegador
# enviar cookies al backend:
varnishlog -b -i TxURL,TxHeader -o TxHeader Cookie 

# Ver las transacciones que vengan del cliente e incluyan /images en la URL:
varnishlog -c -m 'RxURL:^/images

# Logar todas las peticiones que tomen mas de 10 segundos en generarse:
varnishlog -o -i Backend,RxURL,ReqEnd,RxHeader? | \ 
 perl -ne 'BEGIN { $/= "";} print if 
 (/ReqEnd(?:[\sc]+)\d+\s\d+.\d+\s+\d+.\d+\s+\d+.\d+\s+(\d+.\d+)/ and $1 > 10.0)' 

Si preferimos sacar los logs a disco, podemos modificar los siguientes ficheros para hacerlo:

RPM: /etc/sysconfig/varnishlog y /etc/sysconfig/varnishncsa
APT: /etc/default/varnishlog y /etc/default/varnishncsa


Varnishstat : estadísticas en tiempo real

varnishstat proporciona estadísticas en tiempo real de una instancia varnishd en ejecución. Nos proporciona información, entre otras cosas, sobre los hits y misses en caché, hilos creados, objetos creados y eliminados, conexiones de clientes, conexiones correctas al backend, fallos de conexión al backend, estado del almacenamiento/caché, etc.

El funcionamiento es similar a top (las estadísticas se actualizan 1 vez por segundo, o cada X segundos con -w X) a menos que indiquemos el flag -1 (realizar una sóla ejecución y salir).

Veamos el aspecto que tiene la salida de varnishstats:

0+00:12:17
Hitrate ratio:        1        1        1
Hitrate avg:     0.0392   0.0392   0.0392

          21         0.00         0.03 client_conn - Client connections accepted
          58         0.00         0.08 client_req - Client requests received
           2         0.00         0.00 cache_hit - Cache hits
          49         0.00         0.07 cache_miss - Cache misses
          11         0.00         0.01 backend_conn - Backend conn. success
           1         0.00         0.00 backend_fail - Backend conn. failures
          44         0.00         0.06 backend_reuse - Backend conn. reuses
          49         0.00         0.07 backend_recycle - Backend conn. recycles
          50         0.00         0.07 fetch_length - Fetch with Length
           2         0.00         0.00 fetch_chunked - Fetch chunked
           5         0.00         0.01 fetch_failed - Fetch failed
           2         0.00         0.00 fetch_304 - Fetch no body (304)
          22          .            .   n_sess_mem - N struct sess_mem
          43          .            .   n_object - N struct object
          51          .            .   n_objectcore - N struct objectcore
          51          .            .   n_objecthead - N struct objecthead
          11          .            .   n_waitinglist - N struct waitinglist
           5          .            .   n_vbc - N struct vbc
          10          .            .   n_wrk - N worker threads
          11         0.00         0.01 n_wrk_create - N worker threads created
           7         0.00         0.01 n_wrk_queued - N queued work requests
           1          .            .   n_backend - N backends
           2          .            .   n_lru_moved - N LRU moved objects
          54         0.00         0.07 n_objwrite - Objects sent with write
          21         0.00         0.03 s_sess - Total Sessions
          58         0.00         0.08 s_req - Total Requests
           7         0.00         0.01 s_pass - Total pass
          49         0.00         0.07 s_fetch - Total fetch


La primera línea es el uptime de la instancia de Varnish. Las siguientes 2 líneas nos indican el ratio de aciertos en caché que tiene nuestro acelerador HTTP en los anteriores 10, 100 y 1000 segundos. El valor que nos interesa en estas 2 líneas es el de "Hitrate avg:", que nos proporcionará el valor medio normalizado de aciertos en caché (multiplicar por 100 para obtener un porcentaje).

Este valor indica cuántos la proporción de hits vs misses en caché. Hay que tener en cuenta que "pass" no es un cache_miss, por lo que podemos tener un valor medio de hitrate de 100% (1.0) y aún así seguir viendo entrar peticiones al backend HTTP.

Tras esto, viene el listado de contadores específico, especificados con su nombre en Varnish (client_conn) y una breve descripción (Client connections accepted).

Cada uno de estos contadores tiene 3 columnas: la primera es el valor en crudo del contador (valor total), la segunda es el valor por segundo en tiempo real, y la tercera el valor medio por segundo desde que se arrancó varnishd.

Los contadores que no tienen segunda y tercera columna son debidos a que son contadores que pueden decrecer, por lo que los valores por segundo y medias no son datos útiles.


Otras herramientas para análisis de logs/rendimiento

Además de varnishlog y varnishstat, las siguientes herramientas pueden resultar muy útiles para ayudarnos a mejorar la configuración y por tanto el ratio de aciertos en caché de nuestra web:


varnishncsa

varnishncsa es similar a varnishlog (acepta las mismas opciones de filtrado), pero muestra los logs en formato NCSA, es decir, similares a los de Apache y NGINX, con su IP de origen, fecha/hora, tipo de petición, protocolo, código devuelto, tamaño, referer y User-Agent. De esta forma, podemos utilizar estos logs en alguna herramienta de análisis de logs "estándar".


varnishtop

varnishtop lee los logs de varnish en memoria compartida y presenta una lista continuamente actualizada de las entradas de log que más apariciones tienen. Utilizando los filtros (flags de línea de comandos) adecuados, podemos obtener así información sobre el "top" de documentos web más pedidos, de User-Agents, de clientes HTTP, etc.

Por ejemplo:

# Lista de URLs más pedidas por los clientes HTTP
varnishtop -i rxurl

# Lista de URLs más pedidas al backend HTTP (¡ESENCIAL!)
varnishtop -i txurl

# Lista de Accept-Encoding más solicitados:
varnishtop -i RxHeader -I Accept-Encoding


varnishhist y varnishsizes

varnishhist lee los logs de Varnish en memoria y muestra un histograma mostrando la distribución de las últimas N peticiones por tiempo de procesamiento. Los hits en caché se marcan con el carácter | y los misses con #,

varnishsizes es el equivalente de varnishhist pero mostrando el tamaño de los objetos en lugar del tiempo de procesamiento.



Arquitectura interna de Varnish (para tunning)

Internamente, Varnish tiene principalmente 2 procesos:


  • Management Process → Encargado de la inicialización de Varnish, la compilación del VCL, la áplicación de los cambios de configuración en caliente, la monitorización interna de "salud" de sus procesos internos y quien proporciona la interfaz de línea de comandos, telnet y web.
  • Child Process → Encargado de diferentes threads (hilos) de trabajo, incluyendo aceptar nuevas peticiones y delegarlas, gestión de los purges/bans, gestión de la eliminación de objetos de la caché, etc.


Es importante destacar que el Management Process controla constamente la saluda del Child Process y si éste cae lo vuelve a levantar en apenas unos segundos, lo que puede enmascarar "caídas" en Varnish como "problemas de rendimiento" (en recreación de caché). La forma adecuada de distinguir si tenemos "problemas" en Varnish debe empezar por verificar con varnishstat el "uptime" de Varnish, y los logs de syslog, para descartar que se estén produciendo caídas y restarts de los procesos hijos.

A nivel de parámetros de configuración de hilos y memoria asignada a funciones, estos son los parámetros más importantes que podemos modificar:


  • thread_pools → Número de pools para atención de nuevas peticiones y delegación en los threads de gestión. Por defecto es 2 y íla documentación de Varnish no recomienda aumentarlo porque este valor es suficiente hasta para las mayores cargas.
  • thread_pool_min y thread_pool_max → Número mínimo y máximo de hilos que ejecutarán las peticiones (por defecto 5 y 500 respectivamente). Debemos asegurarmos un valor mínimo capaz de soportar la carga "habitual" de la web y un máximo de entre 500 y 2000 threads (hasta 5000 en casos muy excepcionales, y asumiendo que en ese caso las mejoras pueden venir más bien en la parte de la lógica VCL). Podemos ver si tenemos suficientes threads con varnishstat, mirando el contador N queued work requests (n_wrk_queued), que debería ser bastante estable si no necesitamos aumentar los threads.
  • sess_workspace → Tamaño máximo del área de trabajo para gestión de una conexión/cabeceras HTTP del cliente. Por defecto puede ser desde 16KB hasta 10MB. Puede ser necesario aumentarlo en algunos casos y especialmente si usamos procesimiento ESI.
  • connect_timeout (del backend) → El timeout para la conexión con un backend es de 0.7s por defecto, valor que puede ser suficiente si el backend está en la misma red que Varnish pero que puede ser necesario aumentar para backends no cercanos geográficamente o con cierta latencia en la conexión.


En la siguiente sección (Diferencias entre Varnish 2.x y 3.x) veremos cómo se relacionan thread_pool, thread_pool_min y thread_pool_max para calcular el número máximo de threads.



Diferencias entre Varnish 2.x y 3.x

A continuación se muestra una tabla extraída del "Varnish Book" con las diferencias entre Varnish 2.1 y 3.0:


Varnish 2.1 Varnish 3.0
En vcl_fetch: return(pass); En vlc_fetch: return(hit_for_pass);
purge(…); ban(…);
C{ VRT_Nuke(…); }C purge;
"cadena1" "cadena2" "cadena1" + "cadena2"
set req.url = "/test" req.url set req.url = "/test" + req.url
log "algo"; import std; std.log("algo");
"%2520" = literal %20 No necesario escapar '%' →"%20"
set req.hash += req.url; hash_data(req.url);
esi; set beresp.do_esi = true;
thread_pool_max no depende de thread_pools. thread_pool_max en función de thread_pools.
thread_pool_min sí depende de thread_pools. thread_pool_min en función de thread_pools.
thread_pool_max=200 y thread_pools=8
→ 200 threads en total.
thread_pool_max=200 y thread_pools=8
→ 1600 threads en total.




En resumen

Este tutorial es una introducción básica a Varnish, y sólo pretende explicar qué es y para qué sirve, la lógica de procesado de las peticiones, los fundamentos del lenguaje VCL (junto a un pequeño ejemplo de configuración de cacheo de imágenes) y algunos binarios básicos para lectura de logs, estadísticas y troubleshooting.


A partir de este punto, si queremos mejorar el Cache-Ratio de nuestra plataforma web es necesario profundizar en:


  • Gestión de las Cookies, Vary y del Encoding (compresión).
  • Funcionamiento del Purging (purgado de contenido de la caché).
  • Selección de backends (directors, health checks).
  • ESI (Edge Side Includes), o "procesado de la página en porciones" (con diferentes cacheos).
  • Ver múltiples ejemplos para tareas concretas (normalizar Host, manipular el hash, etc.)


No obstante, es importante destacar que Varnish, como todas las herramientas que suponen un punto de inflexión del rendimiento en un plataforma, requiere también una serie de estudios previos para evitar que su implantación afecte negativamente a nuestra Web. Me refiero, esencialmente, a cachear contenido que no deba ser cacheado, como pueda ser la publicidad/banners o secciones de la web que requieran tiempo real. No es positivo para la plataforma Web el perder ingresos por publicidad o que los usuarios detecten que no se actualiza un cajetín de "chat", por ejemplo, debido al cacheo.

Una primera fase de implantación de Varnish debería realizarse en el puerto 82 (atacando al servidor Web original en el 80) y con una configuración conservadora; por ejemplo, cachear sólo las imágenes y contenidos estáticos eliminando las cookies enviadas por el cliente para estos contenidos. Una vez hecho esto, se debe probar la Web y verificar qué impacto en el ratio de acierto en caché tiene esta configuración.

La segunda fase (cacheo de contenidos dinámicos) debería realizarse haciendo primero uso de las herramientas de varnish para obtener información de las URLs dinámicas más llamadas y en cuáles de ellas podemos ofrecer cacheo. También puede ser necesario "visitar" esas URLs y ver la estructura de esas páginas para detectar si alguna de ellas no es susceptible de ser cacheada.

Ambas fases requieren conocimiento de la estructura y funcionamiento de la Web; es complicado montar Varnish delante de una Web cuya arquitectura o estructura no conocemos: si lo hacemos (siempre en un puerto "de pruebas", como el 82), deberemos utilizar varnishtop, varnishstats y varnishlog para decidir qué cachear y cómo.



<Volver a Página de VARNISH>