如何指示 Varnish 根据响应 header 进行缓存?

How do I instruct Varnish to cache based on response header?

我在整个站点的各种 URL 上有一系列视频。我想用 Varnish 缓存它们,即使用户已登录。我可以使用 VCL 配置将某些 URL 列入白名单以进行缓存。但是我不知道如何将所有视频列入白名单。

有没有办法说 return 内容类型为 video/mp4 的所有响应都被缓存了?

决定从缓存中提供 object 和决定在缓存中存储 object 在 Varnish 中是两件不同的事情。这两种情况都需要考虑。

Built-in VCL

为了了解发生了什么 out-of-the-box,您需要查看以下 VCL 文件:https://github.com/varnishcache/varnish-cache/blob/master/bin/varnishd/builtin.vcl

这是执行的built-in VCL。对于每个子例程,当您没有在 VCL 文件中为相应的子例程执行显式 return(xyz) 时,将执行此逻辑。

这意味着您有某种安全网来保护您。

从技术角度来看,在将 VCL 文件编译成 C 代码之前,Varnish 编译器会将 built-in VCL 部分添加到您在 VCL 中扩展的子例程中。

我们从 built-in VCL

中学到了什么

built-in VCL 在可缓存性方面告诉我们以下内容:

  • Varnish 只会从缓存中为 GETHEAD 请求提供 object (参见 vcl_recv
  • 如果 CookieAuthorization header 存在 (参见 vcl_recv),Varnish 将不会从缓存中提供 object
  • 如果 Set-Cookie header 存在,Varnish 将不会在缓存中存储 object (参见 vcl_backend_response
  • 如果 TTL 为零或更小,Varnish 将不会在缓存中存储 object (参见 vcl_backend_response
  • 如果 Cache-Control header 包含 no-store(参见 vcl_backend_response)[=,Varnish 将不会在缓存中存储 object 132=]
  • 如果 Surrogate-Control header 包含 no-cacheno-storeprivate [=114,Varnish 将不会在缓存中存储 object =](参见 vcl_backend_response
  • 如果 Vary header 通过 * [=114] 对所有 header 执行缓存变化,Varnish 将不会在缓存中存储 object =](参见 vcl_backend_response

如何确保从缓存中提供视频文件

vcl_recv 中,您必须确保 Varnish 愿意从缓存中查找视频请求。实际上,这意味着照顾好 cookie。

我的建议是删除所有 cookie,除了您真正需要的那些。下面的示例将删除所有 cookie,但我的后端需要的 PHPSESSID cookie 除外:

vcl 4.1;

sub vcl_recv {
    if (req.http.Cookie) {
    set req.http.Cookie = ";" + req.http.Cookie;
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    set req.http.Cookie = regsuball(req.http.Cookie, ";(PHPSESSID)=", "; =");
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
    
    if (req.http.cookie ~ "^\s*$") {
        unset req.http.cookie;
    }
}

此示例将从请求中删除跟踪 cookie,这很好,因为它们由 Javascript 处理。

PHPSESSID cookie 未设置时,vcl_recv 将退回到 built-in VCL,请求将被处理来自缓存。

但在您的情况下,您希望从缓存中提供它们,即使用户已登录也是如此。这很好,因为视频是不受状态影响的静态文件。

问题是在请求上下文中您不能指定 Content-Type 信息。您必须使用 URL.

示例如下:

sub vcl_recv {
    if(req.url ~ "^/video") {
        return(hash);
    }
}

此代码段将绕过 built-in VCL,如果 URL 与^/video 正则表达式模式。

如何确保视频文件存储在缓存中

当您在 vcl_recv 中执行显式 return(hash) 时,将创建散列并进行缓存查找。但是如果 object 没有存储在缓存中,你仍然会错过,这会导致后端请求。

当后端响应返回时,需要在缓存中保存一定时间。给定 built-in VCL,您必须确保没有指定 zero-TTL,并且 Cache-Control 响应 header 必须return 可缓​​存语法。

这就是我设置 Cache-Control header 的方式,例如,如果我们想要缓存一天的视频文件:

Cache-Control: public, max-age=86400

Varnish 会遵守此 header,并会根据 max-age 语法将 TTL 设置为 1 天。

即使你不指定 Cache-Control header,Varnish 仍会将其存储在缓存中,但为 2 分钟,这是默认的 TTL。

这是一个 Varnish 不会将 object 存储在缓存中的示例,基于 Cache-Control header:

Cache-Control: private, max-age=0, s-maxage=0 ,no-cache, no-store

如果这些表达式中的任何一个在 Cache-Control 中,Varnish 将使 object 不可缓存。

如果 Set-Cookie header 是响应的一部分,object 也变得不可缓存。

如果您不能完全控制后端服务器 return 编辑的 header,您仍然可以在 VCL 中靠运气。

这是一个 VCL 片段,我们强制将 objects 存储在图像和视频的缓存中:

sub vcl_backend_response {
    if(beresp.http.Content-Type ~ "^(image|video)/") {
        set beresp.ttl = 1d;
        unset beresp.http.set-cookie;
        return (deliver);
    }
}

此示例将剥离 Set-Cookie headers,将 TTL 覆盖为一天,并将显式存储和传送 object。只有当 Content-Type 响应 header 以 image/video/

开头时才会出现这种情况