我们正在使用Varnish缓存6.2来位于WebAPI后端的前面。 后端会在某些请求上发回一个缓存控制标头,以便我们可以缓存更长的时间。
但是-后端应该掉下来并保持下来,我们会在一个小时内发送过时的重新验证。
因此,后端中的典型缓存控制响应标头如下:
public, max-age=30, stale-while-revalidate=3600
在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;
}
}
我们面临的问题很简单-Max-Age过期后,即使后端可用,Varnish也不会更新缓存中的项目。 (并且响应发生了变化) 我们已经看到来自Varnish的响应“ Age”标头超过200s且响应错误的问题。我们还看到了“年龄”标头为1-3秒的情况,这表明发生了后台获取(或正常获取)。
这种情况经常发生,以至于我们注意到了-但并非在每个请求中都如此。
我尝试了一个简单的“ pass”,例如Varnish中的以下内容:
sub vcl_recv {
return(pass);
}
但是,这似乎没有效果。
使用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";
}
答案 0 :(得分:2)
这是预期的行为。如果对象是第一次从后端获取的(即t=0
),则Varnish会将其缓存,将beresp.ttl
设置为30s
,将beresp.grace
设置为3600s
。然后,如果您在t=3000
时将对象请求为Varnish,则旧对象将被传递到客户端(即Age: 3000
),并且将触发异步后台获取以刷新缓存的对象。如果您在t=3001
时再次请求对象给Varnish,则如果后台获取已完成其工作,则将交付一个新对象(即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
为了在缓存中的项目消耗完其TTL之后同步刷新对象,您需要在req.grace
期间使用vcl_recv
进行播放。如果后端正常,则可能需要将其设置为0s
。请检查https://varnish-cache.org/docs/trunk/users-guide/vcl-grace.html#misbehaving-servers了解详情。