Dynamic backends in Varnish allow backends to be defined on request time instead of being predefined. For example, any request header can be used as the source for creating a backend definition.
A clear advantage of this is the possibility of DNS-backed server pool that scale up and down to accommodate the load. This is a great feature that fits well with autoscaling cloud deployments. This vmod can currently create and update directors based on:
vmod-goto
integrates with VCL to enable dynamic routing on a per-request
basis.
This API applies to Varnish Enterprise 6.0 and higher.
Note ip addresses from SRV records use the port from the SRV record by default.
The port from the port
argument can be forced by setting port_rule to force
.
goto behaves like vmod-directors: you first create a director object in
vcl_init
that you can then use in vcl_backend_fetch
. In this case, we
create a pool of all the machines answering to the api.example.com
domain:
import goto;
# varnish needs at least one static backend, even if it's null
backend default none;
sub vcl_init {
new apipool = goto.dns_director("api.example.com");
}
sub vcl_recv {
set req.backend_hint = apipool.backend();
}
You can also very easily create an HTTP proxy by resolving the host header to a backend, without creating the director (ie. without knowing the hostname before hand):
import goto;
backend default none;
# goto.dns_backend() can only be used in vcl_backend_* routines
sub vcl_backend_fetch {
set bereq.backend = goto.dns_backend(bereq.http.host);
}
goto has quite a few optional parameters, and these can be specified in any order much like in Python, where each parameter is named:
goto.dns_backend(bereq.http.host, ip_version = ipv6)
goto.dns_director(STRING s, ...)
Produce a director object, a pool of machines listed by the DNS. This pool is regularly updated (every 10 seconds by default) without blocking.
You can query a backend from this director using the .backend()
method.
Internally, the director uses round-robin, so every time it’s used, the returned
backend will change.
goto.dns_backend(STRING s, ...)
Note: It can only be called from backend-side VCL sub-routines. Calling it from anywhere else won’t return a backend.
While the dns()
function solves the problem of resolving a known hostname
for long-term use, sometimes an ephemeral backend is needed. This is the goal
of this function.
It works the same way as dns_director()
except that instead of a director object, it
directly returns a backend to be used immediately. If multiple IPs were
returned by the DNS, calling dns_backend()
multiple times with the same
arguments will cycle through them.
Such backends are cached for at least a ttl period, and can be reused if
dns_backend()
is called with the same arguments. This avoids making a
DNS resolution per call, enabling better performance.
Once a ttl
period has elapsed, two things can occur:
.dns_backend()
isn’t
allowed in vcl_recv() for example: by the time it’s actually used in vcl_fetch
,
the backend structure may already have been destroyed.s
is asynchronously resolved again and the backends stay
cached for another ttl
period.Both functions have the same arguments, and all but the first one are optional. Most of them are simply the same as standard backend definitions, defaults are between parenthesis:
s
didn’t specify the port, use this one. If empty
too, infer it from the protocol (HTTP->80, HTTPS->443).force
, the port will be determined by s
or port
. If abide
,
the port will be determined by SRV record if one has been resolved, otherwise
the port is determined by s
or port
.s
starts with “http://” or “https://”,
this is ignoredgoto.dns_director("example.com", ip_version = ipv6)
abide
, the TTL will be taken from
the DNS resolution. If force
, the TTL will be taken from the TTL parameter.
If morethan
, the TTL will be the resolved TTL if it is more than the TTL
parameter. Otherwise it is set to the TTL parameter. If lessthan
, the TTL
will be the resolved TTL if it is less than the TTL parameter. Otherwise it
is set to the TTL parameter. A local DNS resolution with a ttl_rule = abide
,
will set the backend’s ttl
to 1s. This can be overwritten by using
ttl_rule = force
, which will set the ttl
to the parameter passed into the function.never
skip a backend revalidation. onerror
skips a backend revalidation when there is
an error in the DNS request. onempty
skips a backend revalidation when there is an error
in the DNS request or if the request was successful but returned an empty response
For example, no valid record types were available.vmod_goto
uses /etc/nsswitch.conf
to determine the order of DNS
resolution and /etc/hosts
for local DNS resolution. To configure the number
of retries and timeout time (seconds) edit /etc/resolvconf/resolv.conf.d/tail
with:
options attempts:n
options timeout:n
If neither of the above are present a default of 2 retries and a timeout time of
5 will be set. The number of retries can be between 0 and 5, while timeout time
can be between 0 and 30. For the edits to go into effect, enter sudo resolvconf -u
.
See man resolv.conf
for more information about this configuration.
goto
will internally create regular Varnish backends, meaning you will see
their counters in varnishstat
, as for any other backend. However, contrary to
regular backends, the names must be generated, and you’ll see backends named
following this schema:
$VCL.goto.$SERIAL.($IP).($SCHEME://$DOMAIN:$PORT).(ttl:$TTL)
# e.g.
vcl_20211502_214503.goto.00000042.(15.36.75.156).(https://example.com:443).(ttl:10.000000)
The $SERIAL
element ensures uniqueness in the case a new backend is created
with the same definition as an old one, with both coexisting in varnishstat
for a short time.
vmod-goto
is prebuilt for supported versions and included inside
the varnish-plus
package.
The package contains further usage instructions, accessible using man vmod_goto
.
Contact support@varnish-software.com if you need assistance.