Varnish首次请求返回过时对象的问题及配置调整咨询
Varnish首次请求返回过时对象的问题及配置调整咨询
嗨,我来帮你搞定这个Varnish缓存的问题!你的核心需求很明确:正常情况下必须返回新鲜的JSON文件,只有后端服务器挂了、无法响应的时候,才用缓存里的过时版本兜底。但现在的问题是,长时间没请求后,第一个用户拿到的是旧缓存,Varnish偷偷在后台更新,第二个用户才能拿到新的——这其实是Varnish默认的「stale-while-revalidate」机制在搞鬼:它为了减少用户等待时间,会先返回过期缓存,再异步去后端刷新内容,但这完全不符合你要的「优先新鲜」的要求。
那怎么调整配置呢?你需要修改VCL规则,彻底禁用这种“先返旧再更新”的逻辑,同时保留后端故障时用兜底缓存的能力。具体配置如下:
1. 调整后端响应的缓存规则
首先在vcl_backend_response里,除了保留你原来的TTL和Grace设置,还要关闭stale_while_revalidate,让Varnish不要再偷偷用旧缓存兜底刷新:
sub vcl_backend_response { set beresp.ttl = 1s; # 缓存1秒后过期 set beresp.grace = 99y; # 兜底缓存保留很久 set beresp.stale_while_revalidate = 0s; # 禁用后台刷新时返回旧缓存 }
2. 处理缓存命中但已过期的情况
在vcl_hit里,当检测到缓存已经过期(TTL用完),直接触发去后端获取新鲜内容,而不是返回旧缓存:
sub vcl_hit { if (obj.ttl <= 0) { # 缓存过期了,立刻去后端拿新鲜的 return(fetch); } # 缓存还没过期,直接返回 return(deliver); }
3. 后端故障时启用兜底缓存
最后在vcl_backend_error里,确保当后端真的挂了、无法返回内容时,Varnish会拿出Grace里的旧缓存来响应:
sub vcl_backend_error { # 如果有可用的兜底缓存,返回它 if (obj.grace > 0s) { return(deliver); } # 连兜底缓存都没有的话,返回错误 return(fail); }
这样配置之后,效果就完全符合你的需求了:
- 正常情况下,不管多久没请求,第一个用户的请求都会触发Varnish去后端拿新鲜JSON,拿到后直接返回给用户,不会再返回旧缓存;
- 只有当后端服务器故障、无法响应请求时,Varnish才会拿出Grace里的旧缓存来兜底,保证用户还能拿到内容。
备注:内容来源于stack exchange,提问作者Dan Spirit
相关产品推荐
相关产品推荐

