Cloudfront+Varnish+Drupal10:如何让Varnish主导缓存新鲜度避免回源重验证?
解决方案:通过Varnish配置实现TTL内不回源重验证
完全可以通过Varnish的VCL配置,让它成为缓存新鲜度的唯一仲裁者,在TTL内忽略Cloudfront的重验证请求、不触发回源,完美适配Drupal 10大型站点的缓存策略。
核心思路
Cloudfront的重验证请求(携带If-Modified-Since或If-None-Match头)会触发Varnish回源,我们需要在Varnish的请求处理流程中拦截这类请求:当缓存对象仍在TTL有效期内时,直接返回缓存内容,跳过回源步骤;只有当缓存过期后,才允许重验证请求触发回源。
具体VCL配置示例
# 处理客户端请求阶段 sub vcl_recv { # 仅针对GET/HEAD请求处理重验证逻辑 if (req.method == "GET" || req.method == "HEAD") { # 检测是否是Cloudfront发送的重验证请求 if (req.http.If-Modified-Since || req.http.If-None-Match) { # 标记请求状态,便于日志排查 set req.http.X-Cache-Handling = "Revalidation Attempt"; } } } # 缓存命中阶段 sub vcl_hit { # 当缓存命中且未过期时,忽略重验证请求 if (req.http.If-Modified-Since || req.http.If-None-Match) { if (obj.ttl > 0s) { # 删除重验证头,直接返回缓存内容 unset req.http.If-Modified-Since; unset req.http.If-None-Match; return (deliver); } } } # 后端响应处理阶段 sub vcl_backend_response { # 设置Varnish自身的TTL(根据业务调整,比如1小时) set beresp.ttl = 1h; # 告诉Cloudfront长期缓存,不要主动触发重验证 set beresp.http.Cache-Control = "public, max-age=86400"; # 可选:移除ETag和Last-Modified,彻底避免Cloudfront发起重验证 unset beresp.http.ETag; unset beresp.http.Last-Modified; # 标记Varnish的TTL,便于监控 set beresp.http.X-Varnish-TTL = beresp.ttl; }
配置说明
- vcl_recv阶段:识别Cloudfront的重验证请求并标记,为后续处理做准备。
- vcl_hit阶段:关键逻辑——当缓存对象还在TTL内时,直接删除重验证头,返回缓存,完全跳过回源步骤,确保Varnish的TTL是唯一的新鲜度判断标准。
- vcl_backend_response阶段:设置Varnish自身的缓存有效期,同时给Cloudfront返回长缓存时间的头,让Cloudfront尽可能保留缓存,只在Varnish缓存过期后才会触发更新;移除ETag和Last-Modified可以从根源上减少Cloudfront发起重验证的可能。
额外优化建议
- 配合Drupal的Purge模块使用:当Drupal内容更新时,自动清理Varnish中对应页面的缓存,Cloudfront会在下次请求时获取到Varnish返回的新内容,无需手动清理Cloudfront缓存,大幅降低运维成本。
- 根据业务场景调整TTL:比如首页、高频内容设置较短TTL,低频内容设置较长TTL,平衡缓存新鲜度和性能。
- 启用Varnish的
grace模式:当后端服务临时不可用时,Varnish可以继续返回过期缓存,提升系统可用性。
内容的提问来源于stack exchange,提问作者KBS
相关产品推荐
相关产品推荐

