Hi,

One of our websites usually has quite a low but steady stream of visitors, but 
occationally we get a sudden surge of requests over a very short time period 
(about 1-2 minutes). Varnish seems to handle the load fine, but the backends 
struggle with this. But I have noticed that Varnish doesn't serve the stale 
cached data, but instead shows our synthetic 500 page. This is true even for 
the start page, that definitely existed in the cache. And we have a grace 
period of 10 days, so I it's quite annoying that we can't simply serve the 
stale cached data during this short period.

I have tried picturing the entire flow, following the logic in the vcl, but I 
can't see what we do wrong. And annoyingly I can't reproduce the problem 
locally by simply shutting down the backends (or setting them to unhealthy), 
because whenever I do that I get the stale content served just as intended. 
Could the sheer volume itself cause this, making it impossible to reproduce by 
simply fetching the page a few times in the browser before and after disabling 
the backends? Or is there some edge case that I haven't thought of that is 
causing this?

A simpliedfied version of our vcl is included below, with only the relevant 
parts. But unless I have some blatent problem with the vcl, I think it would be 
good if I learned how to troubleshoot this using the Varnish tools, like 
varnishlog. So that next time this happens, I can use varnishlog etc to see 
what's happening.

Is it possible using varnishlog to find the very first request for a specific 
path ("/" in our case) where it returned the synthetic 500 and put it in the 
cache? And is it also possible to find the request just before that one, for 
the same path. If I could extract those two requests (including all the 
metadata in those transactions) from the djungle of thousands of requests, then 
maybe I can find some explanation why the second request doesn't return the 
stale data.

-----------------------------

sub vcl_hit {
    if (obj.ttl > 0s) {
        // Regular cache hit
        return (deliver);
    } else if (req.restarts == 0 && std.healthy(req.backend_hint)) {
        // Graced cache hit, first attempt.
        // Force cache miss to trigger fetch in foreground (ie synchronous 
fetch).
        set req.http.X-forced-miss = "true";
        return (miss);
    } else {
        // Graced cache hit, previous attempts failed (or backend unhealthy). 
Let the fetch happen in the background (ie asynchronous fetch), and return the 
cached value.
        return (deliver);
    }
}

sub vcl_recv {
    if (req.http.X-cache-pass == "true") {
        return(pass);
    }

    set req.grace = 240h; // 10 day grace
}

sub vcl_backend_response {
    if (bereq.http.X-cache-pass != "true") {
  if (beresp.status < 400) {
     set beresp.grace = 240h;
     set beresp.ttl = 30m; // Cache invalidation in the form of xkey softpurge 
can put objects into grace before the TTL is past.
        } else if (beresp.status < 500) {
            set beresp.ttl = 1m;
            return (deliver);
        } else if (beresp.status >= 500) {
            // In some cases we want to abandon the backend request on 
500-errors, since it otherwise would overwrite the cached object that still is 
usefull for grace.
            // This will make it jump to vcl_synth with a 503 status. There it 
will restart the request.
            if (bereq.is_bgfetch) {
                // In grace period. Abandoning 5xx request, since it otherwise 
would overwrite the cached object that still is usefull for grace
                return (abandon);
            } else if (bereq.http.X-forced-miss == "true") {
                return (abandon);
            }
            // Non background fetch, ie no grace period (and no stale content 
available). Cache the error page for a few seconds.
            set beresp.ttl = 15s;
            return (deliver);
        }
    }
}

sub vcl_synth {
    if (req.http.X-forced-miss == "true" && resp.status >= 500) {
        return (restart);
    }
}

sub vcl_backend_error {
    if (bereq.is_bgfetch || bereq.http.X-forced-miss == "true") {
        // By calling abandon, it will jump to vcl_synth with a 503 status. 
There it will restart the request.
        return (abandon);
    }
    set beresp.http.Content-Type = "text/html; charset=utf-8";
    set beresp.ttl = 15s;
    synthetic(std.fileread("/etc/varnish/500.html"));
    return (deliver);
}

-----------------------------
_______________________________________________
varnish-misc mailing list
[email protected]
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-misc

Reply via email to