/ varnish

How to configure HA for Varnish without Varnish Plus

Based on Guy's Blog here's a slightly smaller and simpler setup for Varnish HA without the use of Varnish Plus. Thanks to Guy for his article.

The whole solution is based on the idea to setup multiple, in this case two, Varnish instances which are primary backends to each other. If a request can't be answered by your first Varnish it will ask the second one and only if this call misses your real backend is being queried.

Setup

                     +------------------+
                     |                  |
                     |   Loadbalancer   |
                     |                  |
                     +------------------+
                               |
                  --------------------------
                  |                        | 
          +---------------+        +---------------+
          |               |        |               |
          |   Varnish 1   |        |   Varnish 2   |
          |               |        |               |
          +---------------+        +---------------+
                  |                        |
                  --------------------------
                               |
                     +------------------+
                     |                  |
                     |      Backend     |
                     |                  |
                     +------------------+

Varnish Config

First, define your backends:

# define the other cache servers
backend cache_server {
    .host = "{{ cache_server }}";
    .port = "8888";
}

# define app server
backend app_server {
    .host = "{{ backend_ip }}";
    .port = "8080";
}

Than add the magic in your vcl_recv like this:

sub vcl_recv {
    # rule that directs traffic that has not come
    # from the other cache server to the other cache server
    if (client.ip != "{{ cache_server }}") {
      set req.backend_hint = cache_server;
    }
    else {
      set req.backend_hint = app_server;
    }
}

Additionally I'd like to set some headers which really helps debugging:

sub vcl_deliver {
  # Add Header if cache hit or miss
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT";
  } else {
    set resp.http.X-Cache = "MISS";
  }

  # Add a header to identify which cache server delivered the response
  set resp.http.Server = "{{ active_cache }}";
}

That's it :)

It’s not perfect, but it’s a nice way reducing backend requests, it means you populate 2 caches with 1 backend request, and if you need to restart a cache most of the content should be served from another cache instead of your slow backend.

Thanks again to Guy's Blog for the hint 👍