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:
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; }