Varnish - stale-while-revalidate 似乎不会重新验证

use*_*708 1 caching cache-control varnish

我们使用 Varnish 缓存 6.2 位于 WebAPI 后端前面。后端会根据某些请求发送回缓存控制标头,以便我们可以缓存更长时间。

但是,如果后端出现故障并保持故障状态,我们会发送一个小时的 stale-while-revalidate。

因此,来自我们后端的典型缓存控制响应标头如下所示:

public, max-age=30, stale-while-revalidate=3600
Run Code Online (Sandbox Code Playgroud)

在我们的 Varnish VCL 中,我们添加了一个例程,可以在出现某些错误时停止后台获取。这是为了阻止后端的错误响应进入缓存:

sub vcl_backend_response {
    if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504)
    {
        if (bereq.is_bgfetch)
        {
            return (abandon);
        }

        set beresp.ttl = 1s;
    }
}
Run Code Online (Sandbox Code Playgroud)

我们面临的问题很简单——即使后端可用,Varnish 在 Max-Age 过期后也不会更新缓存中的项目。(并且响应发生了变化)我们已经看到了 Varnish 的响应“Age”标头超过 200 秒的问题,并且响应错误。我们还看到“Age”标头为 1-3 秒的情况,这表明发生了后台提取(或正常提取)。

这种情况发生的频率足以让我们注意到——但并不是每个请求都会发生。

我尝试过简单的“pass”,例如 Varnish 中的以下内容:

sub vcl_recv {
    return(pass);
}
Run Code Online (Sandbox Code Playgroud)

然而,这似乎没有效果。

Varnish 设置是否还有其他问题可能导致上述情况?

编辑,根据评论,这是我们添加到与我们的请求交互的每个子中的一个小东西,以查看实际发生的情况:

sub vcl_deliver {
    if (obj.uncacheable) {
        set req.http.x-cache = req.http.x-cache + " uncacheable" ;
    } else {
        set req.http.x-cache = req.http.x-cache + " cached" ;
    }

    set resp.http.x-cache = req.http.x-cache;
}

sub vcl_hit {
    set req.http.x-cache = "hit";
}
Run Code Online (Sandbox Code Playgroud)

Car*_*lde 5

这是预期的行为。一旦对象第一次从后端获取(即t=0),Varnish 会将其缓存设置beresp.ttl30sberesp.graceto 3600s。然后,如果您在 时向 Varnish 请求对象t=3000,旧对象将被传递到客户端(即Age: 3000),并且将触发异步后台获取以刷新缓存的对象。如果您在 时再次向 Varnish 请求对象t=3001,如果后台获取已经完成其工作,则会传递一个新对象(即Age: 1)。以下测试说明了此行为:

varnishtest "..."

server s1 {
    rxreq
    txresp -hdr "Cache-Control: public, max-age=1, stale-while-revalidate=60" \
           -hdr "Version: 1"

    rxreq
    txresp -hdr "Cache-Control: public, max-age=1, stale-while-revalidate=60" \
           -hdr "Version: 2"
} -start

varnish v1 -vcl+backend {
} -start

client c1 {
    txreq
    rxresp
    expect resp.http.Version == 1
    expect resp.http.Age == 0

    delay 5.0

    txreq
    rxresp
    expect resp.http.Version == 1
    expect resp.http.Age == 5

    delay 0.1

    txreq
    rxresp
    expect resp.http.Version == 2
    expect resp.http.Age == 0
} -run

varnish v1 -expect client_req == 3
Run Code Online (Sandbox Code Playgroud)

为了在缓存中的项目消耗其 TTL 后同步刷新对象,您需要使用req.gracewhile vcl_recv0s如果后端运行正常,您可能希望将其设置为。请查看https://varnish-cache.org/docs/trunk/users-guide/vcl-grace.html#misbehaving-servers了解详细信息。