如何根据 Varnish 中的大小进行缓存?

How to cache based on size in Varnish?

我一直在尝试根据清漆的响应大小进行缓存。
其他答案建议使用 Content-Length 来决定是否缓存,但我使用的是 InfluxDB(Varnish 反向代理)并且它以 Transfer-Encoding:Chunked 响应,它省略了 Content-Length header 而且我无法计算出响应的大小。
有什么方法可以访问响应 body 大小并在 vcl_backend_response 中做出决定?

缓存未命中:分块传输编码

当 Varnish 处理来自源的传入块时,它无法提前知道将接收到多少数据。 Varnish 将数据流式传输到客户端并按字节存储数据字节。

一旦收到 0\r\n\r\n 标记流的结束,Varnish 将最终确定 object 存储并计算总字节数。

缓存命中:内容长度

下次请求 object 时,Varnish 不再需要使用 Chunked Transfer Encoding,因为它在缓存中有完整的 object 并且知道大小。那时 Content-Length header 是响应的一部分,但是这个 header 在 VCL 中无法访问,因为它似乎是在执行 sub vcl_deliver {} 之后生成的。

事后删除 object 秒

通过 VSL 监控它们的大小,可以事后删除 objects。

以下命令将查看 VSL 输出的后端请求记帐字段并检查总大小。如果大小大于 5MB,则生成输出

varnishlog -g request -i berequrl -q "BereqAcct[5] > 5242880"

这是一些潜在的输出:

*   << Request  >> 98330
**  << BeReq    >> 98331
--  BereqURL       /

此时,您知道 / 资源大于 5 MB。然后您可以尝试使用以下命令将其从缓存中删除:

varnishadm ban "obj.http.x-url == / && obj.http.x-host == domain.com"

Replace domain.com with the actual hostname of your service and set / to the URL of the actual endpoint you're trying to remove from the cache.

不要忘记将以下代码添加到您的 VCL 文件中,以确保 x-urlx-host header 可用:

sub vcl_backend_response {
    set beresp.http.x-url = bereq.url;
    set beresp.http.x-host = bereq.http.host;
}

sub vcl_deliver {
    unset resp.http.x-url;
    unset resp.http.x-host;
}

结论

虽然没有 turn-key 解决方案来访问 VCL 中 body 的大小,但我建议的 hacky 解决方案是我们在事后删除 objects 的唯一方法我能想到。