0

I know there are a lot of questions and answers on this topic. But most of them are for Varnish 3 or don't use the round_robin director.

  • I have 2 webservers configured in Varnish.
  • Some static files may only be generated at one of the two webservers.
  • On a 404 response, I want varnish to try the other webserver.

Currently i've tested with the following VCL:

sub vcl_init {
    new bar = directors.round_robin();
    bar.add_backend(cbweb1);
    bar.add_backend(cbweb2);
}

sub vcl_recv {
    set req.backend_hint = bar.backend();

    unset req.http.Cookie;
}

sub vcl_deliver {
    if(resp.status == 404 && req.restarts < 1)
    {
        return(restart);
    }
}

In my small test, this appears to work. But I don't understand how this works.

Does the bar.backend() remembers which servers have been used and skips those? Or is this just round-robinning globally, is it possible, a server would be called twice if another requests comes in during processing?

Update: The following VCL appears to work:

sub vcl_init {
    new bar = directors.round_robin();
    bar.add_backend(cbweb1);
    bar.add_backend(cbweb2);
}

sub vcl_recv {
    set req.backend_hint = bar.backend();
}

sub vcl_backend_fetch
{
    if (bereq.retries > 0)
    {
        if(bereq.http.X-Backend == "cbweb1")
        {
            set bereq.backend = cbweb2;
        }
        else
        {
             set bereq.backend = cbweb1;
        }
    }
}

sub vcl_backend_response {
    set bereq.http.X-Backend = beresp.backend.name;

    if (beresp.status == 404 && bereq.retries < 1) {
        return(retry);
    }
}
Saa
  • 1,540
  • 10
  • 22

1 Answers1

1

I think it works in your test because of round robin. It will try servers one after each other.

I think in a production setup this won't work because of concurrent requests.

If you retry, it will go again through the vcl_recv and get a backend_hint from the director, whatever is the req.restarts value. If you want a different backend then you will have to code it.

An idea could be (code not tested, you will have to adapt the X-backend comparison):

sub vcl_init {
    new bar = directors.round_robin();
    bar.add_backend(cbweb1);
    bar.add_backend(cbweb2);
}

sub vcl_recv {
    if (req.restarts > 0){
      if (req.X-backend == cbweb1 ){
        set req.backend_hint = cbweb2;
      }
      if (req.X-backend == cbweb2 ){
        set req.backend_hint = cbweb1;
      }
    }
    else {
      set req.backend_hint = bar.backend();
    }
    set req.X-backend = req.backend_hint

    unset req.http.Cookie;
}

sub vcl_deliver {
    if(resp.status == 404 && req.restarts < 1)
    {
        return(restart);
    }
}
Benjamin Baumann
  • 4,035
  • 2
  • 25
  • 35
  • Thanks; this looks promising. Still need some code-help though. `set req.http.X-backend = req.backend_hint` gets 'bar' value (my director name, not the backend name). In vcl_backend_response I can access beresp.backend.name, but this is not available in vcl_recv, neither is req.backend. – Saa Feb 28 '17 at 18:21
  • 1
    you should make the restart logic in vcl_backend_response. There you can set req.http.X-Backend to beresp.backend.name. in vcl_recv you will be able to query req.http.X-backend – Benjamin Baumann Feb 28 '17 at 18:47
  • Thanks; your answer combined with http://stackoverflow.com/questions/35470333/change-backend-during-retry-in-varnish-4 gave me a possible solution (didn't test with concurrent requests yet). Will edit my question for other readers. – Saa Mar 01 '17 at 07:31