我们的设置遇到了问题,Varnish 开始提供空白页。我们在 varnish 之前终止 ssl,并在其后面使用 apache2.4+php-fpm over fcgi 设置。
乍一看,这些页面似乎只出现在旧版应用程序中,我们注定要使用 php5.6,因此可能会得到白页。但这些错误是随机发生的。php7.2 应用程序也受到了影响。
下一个猜测是关于我们这边 Apache 的最近变化(互斥类型)。结果也是错误的。
启用缓存解决了这个问题,但并不是解决方案。
所有互联网搜索都暗示了 Content-Encoding: chunked 与错误的 http 版本之间存在关联,但经过检查,我们在 varnish 之前和之后都使用了 http/1.1。我们也随机遇到了这个问题(约 0.6% 的页面)。
(我写这篇文章是想提出一个问题,以便为下一个与这种怪现象作斗争的可怜人提供答案。但不知何故,以前从来没有人质疑过这个问题。)
答案1
我在测试过程中找到了解决方案:
我使用 curl 和 less 在多台机器上进行了测试。但有时我使用-I
,从而触发 HEAD 请求。事实证明,就缓存而言,HEAD 请求被视为 GET 请求(相同的缓存键),但后端只是对 head 请求做出无正文响应。因此,您最终会得到没有正文的缓存对象,这也会触发 GET 请求的 HIT。
我只需将这一行添加到 vcl_hash 中,问题就解决了:
hash_data(req.method); // cache HEAD requests seperately
希望这可以帮助其他人节省两周的调试时间。
答案2
Varnish 如何处理HEAD
请求
Varnish 的默认行为是接受一个HEAD
请求,并将其转变为一个GET
请求。
响应存储在缓存中,但在返回给客户端之前有效负载已被剥离。
这是出于效率考虑而设计的,并且不违反 RFC。输出应该相同。
Varnish 不会根据请求方法添加缓存变体。由于HEAD
转换为GET
,因此不需要该变体。
如何规避这种默认行为
在您的具体案例中,您已在源级别进行了优化以处理HEAD
请求。显然,HEAD
在源端接收纯净、无杂质的请求很重要。
为了实现这一点并规避默认行为,有两种常用方法:
您可以明确地将请求方法设置HEAD
为vcl_backend_fetch
:
sub vcl_recv {
set req.http.method = req.method;
}
sub vcl_hash {
hash_data(req.http.method);
}
sub vcl_backend_fetch {
if(bereq.http.method == "HEAD") {
set bereq.method = "GET";
}
unset bereq.http.method;
}
您可以绕过缓存:
sub vcl_recv {
if(req.method == "HEAD") {
return(pass);
}
}
在您的情况下,前一种解决方案可能比后一种解决方案更好。
你的 VCL 中发生了一些事情
尽管您声称没有 VCL 逻辑可以保持HEAD
请求完整,但我怀疑您的 VCL 中发生了一些事情。
我很想看看你的完整 VCL 文件,并亲自尝试一下。请随意删除任何敏感数据。
我确实同意你的问题的解决方案。
尽管我很难相信您的 Varnish 安装可以HEAD
在没有任何特殊 VCL 的情况下保持请求完整,但您提供的解决方案是有效的。
为每个请求方法创建缓存变体是解决问题的好方法。
无论您是否为HEAD
请求准备了特殊的 VCL,这都是满足原始服务器需求的行为。我不会争论这一点。
我研究这个话题的唯一原因是我对导致这个问题的原因感兴趣。您已经提供了解决方案,我只是想确保我们都明白为什么事情会这样发生。
期待该 VCL 文件,并感谢您的输入。