为什么 Varnish 获取速度比绕过 Varnish 慢得多?

Why is Varnish fetch significantly slower than bypassing Varnish?

我已将 Varnish(端口 80)设置为缓存来自 Node.js 服务器(端口 8080)的请求,该服务器通常在个位数毫秒内响应(但有时会长得多)。

我在 PHP 中设置了一个简单的基准(我知道一次只会发送一个请求):

// Measure time for backend (bypassing Varnish by using port 8080)
$t = microtime(true);
foreach ($requests as $request){
  file_get_contents($request["url"] . ":8080/?" . http_build_query($request["parameters"]));
}
$t = microtime(true) - $t;
echo "Backend: " . $t . "\n";

// Measure time for Varnish (using port 80 after Varnish restart)
$t = microtime(true);
foreach ($requests as $request){
  file_get_contents($request["url"] . ":80/?" . http_build_query($request["parameters"]));
}
$t = microtime(true) - $t;
echo "Varnish MISS: " . $t . "\n";

// Measure time for Varnish (now cached)
$t = microtime(true);
foreach ($requests as $request){
  file_get_contents($request["url"] . ":80/?" . http_build_query($request["parameters"]));
}
$t = microtime(true) - $t;
echo "Varnish HIT: " . $t . "\n";

// Results:
Backend: ~10 seconds
Varnish MISS: ~65 seconds
Varnish HIT: ~2 seconds

我测试了大约 1400 个请求。平均而言,Varnish 会为每个错过的请求增加 30-40 毫秒的开销。

Varnish 中缓存未命中的开销似乎大得惊人,我发现其他人也报告了类似的结果 - 然而,没有人能够解释为什么或如何减少开销。

所以我的问题是,为什么会有这么大的开销,我该如何减少它?

我知道缓存的想法是避免优化初始请求的响应时间,但是这个特定的网络服务会在短时间内看到大量的独特请求(但很多重新- 几天的请求),因此 Varnish 的开销有点重要。

清漆设置

vcl 4.0;

# Default backend definition. Set this to point to your content server.
backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_recv {
    unset req.http.Cookie;
}

sub vcl_backend_response {
}

sub vcl_deliver {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }
}

在向 Varnish 人员询问了这个问题后,他们建议我尝试在同一台服务器但不同的后端上复制它。尝试使用 Apache 后端没有问题。

仔细检查来自 Varnish 的响应,我注意到对于 Node.js 服务器,在快速完成但没有完成的请求上会有 Content-Length header(由 Varnish 设置)关于那些完成缓慢的。

将 Content-Length header 添加到 Node.js 服务器响应(在 Apache 中默认添加)解决了这个问题。