Load Balancing / HA - Múltiples backends en Varnish

Varnish permite la definición y utilización de múltiples backends HTTP, ya sea por selección manual (en base a Host o URL), por balanceo de carga o por "disponibilidad" de los mismos ("probe").

El primer caso (selección manual) se basa en la utilización de expresiones regulares sobre la URL o el HOST para decidir el uso de uno u otro backend.

El resto de casos se basan en las capacidades de Balanceo de carga o Alta Disponibilidad de Varnish, es decir, en la utilización del director, un backend virtual que agrupa varios backends con ciertas propiedades de "prueba" y "balanceo".


En muchos casos puede darse la ocasión de que tengamos los contenidos distribuídos entre varios servidores HTTP. Por ejemplo, podemos tener el contenido dinámico PHP en un servidor con Apache + mod_php, y el contenido estático (imágenes, js, css en este ejemplo) en un servidor NGINX aparte.

En ese caso, podemos definir múltiples backends y utilizar uno u otro en vlc_recv() en función de la URL.

En el siguiente ejemplo, se envían todos los datos al backend "apache" excepto aquellas URLs que empiecen por /images/, /layout/, /js/ o /css/, que se envían a un backend alternativo ("estaticos"):

backend apache
{
  .host = "127.0.0.1";
  .port = "8080";
}
 
backend estaticos {
  .host = "172.16.1.2";
  .port = "80";
}

 
sub vcl_recv 
{
    # Contenidos estaticos -> dirigir a un backend diferente
    if (req.url ~ "^/(images|layout|js|css)/" ) 
    {
        unset req.http.Cookie;
        unset req.http.Authenticate;
        set req.backend = estaticos;
        return(lookup);
    }
 
    # El resto, van al backend por defecto (apache):
    set req.backend = apache;
    return(pass);
}

Nótese que a la hora de seleccionar el backend de estáticos, hemos también eliminado las Cookies y las peticiones de Autenticación puesto que nuestro backend de estáticos sólo contiene "ficheros".


El balanceo de carga y alta disponibilidad en Varnish se utiliza mediante un "backend HTTP virtual" llamado director, que agrupa varios backends junto a las pruebas necesarias para determinar si están "sanos" (si responden a peticiones HTTP).

Veamos la definición de 2 backends HTTP de contenido idéntico, y cómo se agrupan en un director para su posterior uso:

backend servidor1 
{
    .host = "172.16.1.2";
    .port = "81";
    .probe = 
    {
        .url = "/";
        .interval = 5s;
        .timeout = 3s;
        .window = 5;
        .threshold = 3;
    }
}

backend servidor2 
{
    .host = "172.16.1.3";
    .port = "81";
    .probe = 
    {
        .url = "/";
        .interval = 5s;
        .timeout = 2s;
        .window = 5;
        .threshold = 3;
    }
}

El parámetro .probe indica a Varnish la forma de testear si el backend está disponible o no. En el anterior ejemplo, se verifica la URL "/" de cada backend cada 5 segundos. Si tarda más de 2 segundos en contestar en más de 3 de las últimas 5 pruebas, se considera que el backend está caído y Varnish no le volverá a mandar peticiones hasta que vuelva a estar de nuevo disponible.

A continuación definimos nuestro "backend virtual" (el director), con el método round-robin (alternar peticiones) o con el método random (envío aleatorio de peticiones a uno u otro backend):

director backends_http round-robin 
{
    {
        .backend = servidor1;
    }
    {
        .backend = servidor2;
    }
}

En el caso de directors de tipo random, podemos indicar un parámetro adicional en los backends llamado .weight (valor de 1 a N) para especificar un peso a cada servidor

director backends_http random 
{
    .retries 2
    {
        .backend = servidor1;
        .weight = 1;
    }
    {
        .backend = servidor2;
        .weight = 1;
    }
}

El parámetro .retries indica el número de intentos que el director realizará para encontrar un backend válido (por defecto, para este y otros métodos de balanceo), es igual al número de backends definidos.

Tras esto, podemos usar el director como cualquier otro backend en las funciones vcl_*(), bien asignándolo directamente, o bien en base a algún match en host o url:

sub vcl_recv 
{
    if (req.http.host ~ "^(www.)?dominio.com$") 
    {
        set req.backend = backends_http;
    }
}

Un apunte: dentro de los directors podemos utilizar (definir) backends no definidos anteriormente:

director nombre metodo
{
   { .backend = backend_uno; }
   { .backend = backend_dos; }
   { .backend = { .host="blah"; .port="82"; } }
}


En la documentación de Varnish se especifican otros métodos de balanceo además de round-robin y random:


  • hash director → Este tipo de "director" seleccionará un backend HTTP en base al hash de la URL. Esto permite usar Varnish como balanceador de otros Varnish y permite que los objetos no sean cacheados en múltiples cachés.
  • dns director → Este tipo de "director" permite definir múltiples backends en base a la propiedad ".list y seleccionar uno u otro en realizando una consulta DNS de la cabecera Host: para determinar si algún backend hace match con él.

El ejemplo para director dns de la página oficial de Varnish es:

director directorname dns 
    {
        .list = 
        {
            .port = "81";
            .connect_timeout = 0.4;
            "192.168.15.0"/24;
            "192.168.16.128"/25;
        }
        .ttl = 5m;
        .suffix = "internal.net";
}

Este código especifica 384 backends, todos con los mismos parámetros de conexión, de forma que se le añade "internal.example.com" al host-header enviado por el cliente, y se consulta esto en el DNS para utilizar el backend resultante por IP.

En el anterior ejemplo, si un cliente HTTP pregunta por "www.dominio.com", Varnish acudirá al DNS y preguntará por la IP de "www.dominio.com.internal.net". Si se obtiene una IP válida y está dentro de los backends definidos en la lista, utilizará ese backend para atender la petición.


Finalmente, a partir de Varnish 2.1.4 se puede balancear en función de alguno de los parámetros del cliente HTTP, como su IP, la URL solicitada o alguna de las cabeceras HTTP enviadas:

director balanceo_cliente client 
{
    {
        .backend = servidor1;
        .weight = 1;
    }
    {
        .backend = servidor2;
        .weight = 1;
    }
}

sub vcl_recv {
   set req.backend = balanceo_cliente;

   // Balancear por IP del cliente (es la accion por defecto):
   set client.identity = client.ip;
   
   // Balancear por URL:
   // set client.identity = req.url;

   // Balancear por User-Agent
   // set client.identity = req.http.user-agent;
}



<Volver a Página de VARNISH>

  • linux/servicios/varnish_backends.txt
  • Última modificación: 07-05-2012 10:16
  • por sromero