You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Varnish中失效URL且保留旧版本至新版本缓存完成

Varnish:标记URL失效但保留旧缓存直到更新完成的最佳实践

核心思路

你的需求本质是**"stale-while-revalidate"模式:标记缓存条目过时,但仍返回旧内容,同时后台异步从后端拉取新版本更新缓存。PURGE会直接删除缓存,不符合需求,应使用BAN**机制配合grace/stale配置实现。


具体实现步骤

1. 配置BAN规则替代PURGE

BAN不会删除缓存条目,只是标记匹配的条目为"过时"。后续请求时Varnish会优先返回旧缓存,同时触发后台刷新。

在vcl_recv中添加BAN处理逻辑

sub vcl_recv {
    # 处理BAN请求(建议通过IP白名单限制调用权限)
    if (req.method == "BAN") {
        # 替换allowed_ban_ips为你的授权IP列表
        if (!client.ip ~ allowed_ban_ips) {
            return (synth(403, "Forbidden"));
        }
        # 通过自定义Header传递要标记的URL,支持模糊匹配(示例为精确匹配)
        ban("obj.http.x-cache-url == " + req.http.X-Ban-Target);
        return (synth(200, "Ban scheduled"));
    }
}

在vcl_backend_response中添加缓存标识与grace配置

给缓存对象打标记,方便BAN精准匹配,同时配置grace时间确保旧缓存可被返回:

sub vcl_backend_response {
    # 给缓存对象绑定URL标识,用于BAN匹配
    set beresp.http.x-cache-url = bereq.url;
    # 设置grace时间,根据业务调整(示例为1小时)
    set beresp.grace = 1h;
    # 可选:开启stale-if-error,后端出错时也返回旧缓存
    set beresp.stale_if_error = 1h;
}

2. 启用后台自动刷新

确保Varnish在返回旧缓存的同时,异步去后端拉取新版本:

sub vcl_hit {
    if (obj.ttl <= 0 || obj.http.X-Banned) {
        # 返回旧缓存,同时触发后端刷新
        return (deliver_stale);
    }
}

sub vcl_deliver {
    # 给响应添加缓存状态标识,方便调试
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }
    # 删除自定义标识头,避免暴露给用户
    unset resp.http.x-cache-url;
}

3. 调用BAN的示例命令

# 标记指定URL为过时
curl -X BAN -H "X-Ban-Target:/product/123" http://your-varnish-host

关键注意事项

  • 权限控制:必须限制BAN请求的来源IP,避免恶意滥用导致缓存雪崩。
  • grace时间配置:要根据后端服务的更新频率和业务容忍度设置,过短可能导致频繁回源,过长可能延迟新版本上线。
  • 避免PURGE:PURGE会直接删除缓存条目,导致后续请求必须等待后端响应,无法实现"先返回旧缓存再更新"的需求。

内容的提问来源于stack exchange,提问作者frlan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 01:42:17