varnish 随机提供空白页

varnish 随机提供空白页

我们的设置遇到了问题,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在源端接收纯净、无杂质的请求很重要。

为了实现这一点并规避默认行为,有两种常用方法:

您可以明确地将请求方法设置HEADvcl_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 文件,并感谢您的输入。

相关内容