Varnish Cache Replication with VCL

If you’re using Varnish then you’ve probably looked into replication for it at some point. The official solution is to buy Varnish Plus and use the HA replication agent, however you can do basic replication with normal Varnish and some VCL magic.

First you need to define a upstream server for all of your Varnish caches except the one you’re configuring, in this case let’s assume we have 4 nodes ServerA, ServerB, ServerC and ServerD and we are configuring ServerA:

# Cache Servers:
backend cache_serverB {
    .host = "serverB";
    .port = "6081";
        }
}
backend cache_serverC {
    .host = "serverC";
    .port = "6081";
        }
}
backend cache_serverD {
    .host = "serverD";
    .port = "6081";
        }
}

Next you need to define a upstream server for each of your actual backends, in our case we have 4 tomcat instances running on the same servers, this time we will include the server we are configuring, as we want to be able to reverse proxy to the local tomcat server:

# Tomcat Servers:
backend tomcat_serverA {
.host = "serverA";
.port = "7080";
}
}
backend tomcat_serverB {
.host = "serverB";
.port = "7080";
}
}
backend tomcat_serverC {
.host = "serverC";
.port = "7080";
}
}
backend tomcat_serverD {
.host = "serverD";
.port = "7080";
}
}

Now we need to create our director groups for all the backends we just created:

# Director Groups
sub vcl_init {

# Cache director group:
    new cache = directors.random();
    cache.add_backend(cache_serverB,1);
    cache.add_backend(cache_serverC,1);
    cache.add_backend(cache_serverD,1);

# Tomcat director group:
    new tomcat = directors.random();
    tomcat.add_backend(tomcat_serverA,90000000);
    tomcat.add_backend(tomcat_serverB,1);
    tomcat.add_backend(tomcat_serverC,1);
    tomcat.add_backend(tomcat_serverD,1);
}

You should set the weight of the server you are configuring to be super high – serverA in this case, because when you do need to go to the back end the local server should be preffered.

Next we need to create a ACL containing all the cache nodes except the one you are configuring:

acl cache_nodes {
        "serverB";
        "serverC";
        "serverD";
}

And now that’s it, set the default backend to the tomcat director group and then in your VCL add a rule that directs traffic that has not come from a server in our cache ACL to the cache director group:

        if (!client.ip ~ cache_nodes) {
                set req.backend_hint = cache.backend();
        }

The result of this is that when a request comes to a cache, if it has not got the object stored locally it will use one of your other caches as a backend, the other cache receiving this request will either serve a cached copy saving you a backend request, or if it doesn’t have a cached copy it will match the client as being in our cache_nodes ACL and fetch the request from the tomcat director group, populating both caches with the object.

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.

Published by

Guy Tabrar

*NIX Admin.