使用 Varnish 加速您的网站
Varnish 是一款程序,可以显著加速网站,同时降低 Web 服务器的负载。根据 Varnish 官方网站的说法,Varnish 是一个“Web 应用程序加速器,也称为缓存 HTTP 反向代理”。
当您从高层次思考 Web 服务器的功能时,它接收 HTTP 请求并返回 HTTP 响应。在理想情况下,服务器会立即返回响应,而无需进行任何实际工作。然而,在现实世界中,服务器可能需要做相当多的工作才能向客户端返回响应。让我们首先看看典型的 Web 服务器是如何处理这种情况的,然后再看看 Varnish 如何改进这种情况。
尽管每个服务器都不同,但典型的 Web 服务器会经历一个可能很长的步骤序列来处理它接收的每个请求。它可能首先生成一个新进程来处理请求。然后,它可能必须从磁盘加载脚本文件,启动解释器进程来解释并将这些文件编译成字节码,然后执行该字节码。执行代码可能会导致额外的工作,例如执行昂贵的数据库查询和从磁盘检索更多文件。将此乘以数百或数千个请求,您就可以看到服务器如何快速变得过载,耗尽系统资源来尝试满足请求。更糟糕的是,许多请求都是最近请求的重复,但服务器可能没有办法记住响应,因此它注定要从头开始为遇到的每个请求重复相同的痛苦过程。
使用 Varnish 的情况略有不同。首先,请求由 Varnish 而不是 Web 服务器接收。然后,Varnish 将查看正在请求的内容,并将请求转发到 Web 服务器(Varnish 称为后端)。后端服务器执行其常规工作,并将响应返回给 Varnish,Varnish 进而将响应提供给发送原始请求的客户端。
如果 Varnish 仅做到这些,那将没有多大帮助。为我们带来性能提升的是,Varnish 可以将其缓存中的后端响应存储起来以供将来使用。Varnish 可以直接从其缓存中快速提供下一个响应,而无需在后端服务器上施加任何不必要的负载。结果是,后端负载显著降低,响应时间缩短,并且每秒可以处理更多请求。使 Varnish 如此快速的原因之一是它将其缓存完全保存在内存中,而不是在磁盘上。这种优化和其他优化使 Varnish 能够以惊人的速度处理请求。但是,由于内存通常比磁盘更有限,因此您必须适当调整 Varnish 缓存的大小,并采取措施不缓存会浪费宝贵空间的重复对象。
让我们安装 Varnish。我将解释如何从源代码安装它,但您可以使用发行版的软件包管理器安装它。Varnish 的最新版本是 3.0.3,这也是我在此处使用的版本。请注意,Varnish 2.x 版本在配置语法上有一些细微的差异,可能会让您感到困惑。请查看 Varnish 网站上的 Varnish 升级页面,以获取版本 2.x 和 3.x 之间更改的完整列表。
缺少依赖项是最常见的安装问题之一。请查看 Varnish 安装页面,以获取构建依赖项的完整列表。
以 root 身份运行以下命令以下载并安装最新版本的 Varnish
cd /var/tmp
wget http://repo.varnish-cache.org/source/varnish-3.0.3.tar.gz
tar xzf varnish-3.0.3.tar.gz
cd varnish-3.0.3
sh autogen.sh
sh configure
make
make test
make install
Varnish 现在安装在 /usr/local 目录下。主二进制文件的完整路径是 /usr/local/sbin/varnishd,默认配置文件是 /usr/local/etc/varnish/default.vcl。
您可以通过运行 varnishd 二进制文件来启动 Varnish。但在执行此操作之前,您必须告诉 Varnish 它要为哪个后端服务器缓存。让我们在 default.vcl 文件中指定后端。如下所示编辑 default.vcl 文件,将值替换为您 Web 服务器的值
backend default {
.host = "127.0.0.1";
.port = "80";
}
现在您可以使用以下命令启动 Varnish
/usr/local/sbin/varnishd -f /usr/local/etc/varnish/default.vcl
↪-a :6081 -P /var/run/varnish.pid -s malloc,256m
这将以守护进程方式运行 varnishd,并将您返回到命令提示符。值得指出的一点是,varnishd 将启动两个进程。第一个是管理器进程,第二个是子工作进程。如果子进程因任何原因死亡,管理器进程将生成一个新进程。
Varnishd 启动选项-f 选项告诉 Varnish 您的配置文件所在的位置。
-a 选项是 Varnish 将侦听来自客户端的传入 HTTP 请求的地址:端口。
-P 选项是 PID 文件的路径,这将使您稍后更容易停止 Varnish。
-s 选项配置缓存的保存位置。在本例中,我们使用 256MB 的内存驻留缓存。
如果您是从软件包管理器安装 Varnish 的,它可能已经在运行。在这种情况下,您可以先停止它,然后使用上面的命令手动启动它。否则,它启动时使用的选项可能与本示例中的选项不同。查看 Varnish 是否正在运行以及它给出的选项的快速方法是使用 pgrep 命令
/usr/bin/pgrep -lf varnish
Varnish 现在会将它接收到的任何请求中继到您指定的后端,可能会缓存响应,并将响应返回给客户端。让我们提交一些简单的 GET 请求,看看 Varnish 会做什么。首先,在单独的终端上运行以下两个命令
/usr/local/bin/varnishlog
/usr/local/bin/varnishstat
以下 GET 命令是 Perl www 库 (libwww-perl) 的一部分。我使用它,以便您可以查看从 Varnish 返回的响应头。如果您没有 libwww-perl,您可以使用带有 Live HTTP Headers 扩展程序的 Firefox 或您选择的另一个工具
GET -Used http://localhost:6081/

图 1. Varnish 响应头
提供给 GET 命令的选项在这里并不重要。重要的是 URL 指向 varnishd 正在侦听的端口。Varnish 添加了三个响应头。它们是 X-Varnish、Via 和 Age。一旦您了解了它们是什么,这些标头就很有用。X-Varnish 标头后将跟一个或两个数字。单数字版本表示响应不在 Varnish 的缓存中(未命中),显示的数字是 Varnish 分配给请求的 ID。如果显示两个数字,则表示 Varnish 在其缓存中找到了响应(命中)。第一个是请求的 ID,第二个是从中填充缓存响应的请求的 ID。Via 标头仅显示请求通过了代理。Age 标头告诉您响应在 Varnish 中缓存了多长时间,以秒为单位。第一个响应的 Age 为 0,后续命中的 Age 值将递增。如果同一页面的后续响应未递增 Age 标头,则表示 Varnish 未缓存响应。
现在让我们看看之前启动的 varnishstat 命令。您应该看到类似于图 2 的内容。

图 2. varnishstat 命令
重要的行是 cache_hit 和 cache_miss。如果您还没有任何命中,则不会显示 cache_hits。随着更多请求的到来,计数器会更新以反映命中和未命中。
接下来,让我们看看之前启动的 varnishlog 命令(图 3)。

图 3. varnishlog 命令
这向您显示了通过 Varnish 的请求和响应的相当详细的信息。Varnish 网站上的文档将日志输出解释如下
第一列是任意数字,它定义了请求。具有相同数字的行是同一 HTTP 事务的一部分。第二列是日志消息的标签。所有日志条目都标有标签,指示正在记录的活动类型。以 Rx 开头的标签表示 Varnish 正在接收数据,Tx 表示正在发送数据。第三列告诉我们这是发送到客户端 (c) 或来自客户端 (c) 的数据,还是发送到后端 (b) 或来自后端 (b) 的数据。第四列是要记录的数据。
varnishlog 具有各种过滤选项,可帮助您找到所需内容。我建议您尝试并熟悉 varnishlog,因为它将真正帮助您调试 Varnish。请阅读 varnishlog(1) 手册页以获取所有详细信息。接下来是一些使用 varnishlog 进行过滤的简单示例。
查看 Varnish 和客户端之间的通信(省略后端)
/usr/local/bin/varnishlog -c
查看 Varnish 和后端之间的通信(省略客户端)
/usr/local/bin/varnishlog -b
查看 Varnish 接收到的标头(客户端的请求标头和后端的响应标头)
/usr/local/bin/varnishlog -i RxHeader
相同的事情,但仅限于客户端的请求标头
/usr/local/bin/varnishlog -c -i RxHeader
相同的事情,但仅限于后端的响应标头
/usr/local/bin/varnishlog -b -i RxHeader
将所有日志消息写入 /var/log/varnish.log 文件并守护进程化
/usr/local/bin/varnishlog -Dw /var/log/varnish.log
从 /var/log/varnish.log 文件读取并显示所有日志消息
/usr/local/bin/varnishlog -r /var/log/varnish.log
最后两个示例演示了将 Varnish 日志存储到磁盘。Varnish 将循环日志保存在内存中以保持快速,但这意味着除非保存到磁盘,否则旧的日志条目将丢失。上面的最后两个示例演示了如何将所有日志消息保存到文件中以供以后查看。
如果您想停止 Varnish,可以使用以下命令执行此操作
kill `cat /var/run/varnish.pid`
这会将 TERM 信号发送到 PID 存储在 /var/run/varnish.pid 文件中的进程。由于这是 varnishd 管理器进程,Varnish 将关闭。
现在您知道如何启动和停止 Varnish,以及检查缓存命中和未命中,自然而然的问题是 Varnish 缓存什么,以及缓存多长时间?
默认情况下,Varnish 对其将缓存的内容持保守态度,但您可以更改大多数这些默认设置。它只会考虑缓存 GET 和 HEAD 请求。它不会缓存带有 Cookie 或 Authorization 标头的请求。它不会缓存带有 Set-Cookie 或 Vary 标头的响应。Varnish 会查看的一个内容是 Cache-Control 标头。此标头是可选的,可能存在于请求或响应中。它可能包含一个或多个以分号分隔的指令列表。此标头旨在应用缓存限制。但是,Varnish 不会根据 Cache-Control 标头更改其缓存行为,但 max-age 指令除外。此指令如下所示:Cache-Control: max-age=n
,其中 n 是一个数字。如果 Varnish 在后端的响应中收到 max-age 指令,它将使用该值来设置缓存响应的过期时间 (TTL),以秒为单位。否则,Varnish 会将缓存响应的 TTL 过期时间设置为其 default_ttl 参数的值,该参数默认为 120 秒。
Varnish 具有带有合理默认值的配置参数。例如,default_ttl 参数默认为 120 秒。varnishd(1) 手册页中完整解释了配置参数。您可能想要更改某些默认参数值。一种方法是使用 -p 选项启动 varnishd。这样做会有一个缺点,即必须停止并重新启动 Varnish,这将刷新缓存。更改参数的更好方法是使用 Varnish 所谓的管理界面。仅当 varnishd 使用 -T 选项启动时,管理界面才可用。它指定管理界面应侦听的端口。您可以使用 varnishadm 命令连接到管理界面。连接后,您可以查询参数并更改其值,而无需重新启动 Varnish。
要了解更多信息,请阅读 varnishd、varnishadm 和 varnish-cli 的手册页。
您可能想要更改 Varnish 缓存的内容以及缓存的时间长度——这称为您的缓存策略。您可以通过编写 VCL 在 default.vcl 文件中表达您的缓存策略。VCL 代表 Varnish 配置语言,这是一种非常简单的特定于 Varnish 的脚本语言。vcl(7) 手册页中完整解释了 VCL,我建议您阅读它。
在更改 default.vcl 之前,让我们考虑一下 Varnish 为满足 HTTP 请求而经历的过程。我称之为请求/响应周期,它始于 Varnish 接收到请求时。Varnish 将解析 HTTP 请求并将详细信息存储在 Varnish 称为 req 的对象中。现在,Varnish 需要完全基于 req 对象做出决定——它应该检查其缓存以查找匹配项,还是仅将请求转发到后端而不缓存响应?如果它决定绕过其缓存,则唯一要做的就是将请求转发到后端,然后将响应转发回客户端。但是,如果它决定检查其缓存,事情会变得更有趣。这称为缓存查找,结果将是命中或未命中。命中意味着 Varnish 在其缓存中为客户端提供了响应。未命中意味着 Varnish 没有要发送的缓存响应,因此唯一合乎逻辑的事情是将请求发送到后端,然后在发送回客户端之前缓存它给出的响应。
现在您已经了解了 Varnish 的请求/响应周期,让我们讨论如何通过更改 Varnish 在该过程中做出的决策来实施您的缓存策略。Varnish 有一组子例程来执行上述过程。这些子例程中的每一个都执行过程的不同部分,子例程的返回值是您告诉 Varnish 接下来要执行的操作的方式。除了设置返回值之外,您还可以检查和更改子例程中的各种对象。这些对象表示诸如请求和响应之类的内容。每个子例程都有一个默认行为,可以在 default.vcl 中看到。您可以重新定义这些子例程,以使 Varnish 按照您想要的方式运行。
Varnish 子例程Varnish 子例程具有默认定义,这些定义在 default.vcl 中显示。仅仅因为您重新定义了其中一个子例程并不意味着默认定义不会执行。特别是,如果您重新定义了其中一个子例程但没有返回值,Varnish 将继续执行默认子例程。所有默认 Varnish 子例程都返回值,因此 Varnish 将它们用作后备是有道理的。
首先要查看的子例程称为 vcl_recv。这在接收到完整的客户端请求后执行,客户端请求在 req 对象中可用。在这里,您可以检查并通过 req 对象更改原始请求。您可以使用 req 的值来决定如何继续。返回值是您告诉 Varnish 要执行的操作的方式。我将把返回值放在括号中,因为它们已得到解释。在这里,您可以告诉 Varnish 绕过缓存并将后端的响应发送回客户端 (pass)。您还可以告诉 Varnish 检查其缓存以查找匹配项 (lookup)。
接下来是 vcl_pass 子例程。如果您在 vcl_recv 中返回 pass,那么这就是您在将请求发送到后端之前的状态。您可以告诉 Varnish 继续按计划进行 (pass),或者在 vcl_recv 子例程中重新启动周期 (restart)。
vcl_miss 和 vcl_hit 子例程根据 Varnish 是否在缓存中找到合适的响应而执行。从 vcl_miss 中,您的主要选项是从后端服务器获取响应并缓存它 (fetch),或者从后端获取响应但不缓存它 (pass)。vcl_hit 是在 Varnish 成功在其缓存中找到匹配响应时您所在的位置。从 vcl_hit 中,您可以在 obj 对象中使用缓存的响应。您可以告诉 Varnish 将缓存的响应发送到客户端 (deliver),或者让 Varnish 忽略缓存的响应并从后端返回新的响应 (pass)。
vcl_fetch 子例程是在您从后端获得新的响应后您所在的位置。响应将在 beresp 对象中对您可用。您可以告诉 Varnish 继续按计划进行 (deliver),或者重新开始 (restart)。
从 vcl_deliver 中,您可以通过将响应传递给客户端并可能也缓存它 (deliver) 来完成请求/响应周期,或者您可以重新开始 (restart)。
如前所述,您在 default.vcl 中的子例程中表达您的缓存策略。返回值告诉 Varnish 接下来要执行的操作。您可以根据许多内容设置返回值,包括请求 (req) 和响应 (resp) 对象中保存的值(如前所述)。除了 req 和 resp 之外,还有一个表示客户端的 client 对象、一个 server 对象和一个表示后端响应的 beresp 对象。重要的是要意识到并非所有对象都在所有子例程中可用。同样重要的是从子例程返回允许的返回值之一。刚开始使用 Varnish 时最难记住的事情之一是哪些对象在哪些子例程中可用,以及合法的返回值是什么。为了更轻松,我创建了几个参考表。它们将帮助您快速上手,而无需预先记住所有内容或每次进行更改时都查阅文档。
表 1. 此表显示了每个子例程中可用的对象。客户端 | 服务器 | req | bereq | beresp | resp | obj | |
vcl_recv | X | X | X | ||||
vcl_pass | X | X | X | X | |||
vcl_miss | X | X | X | X | |||
vcl_hit | X | X | X | X | |||
vcl_fetch | X | X | X | X | X | ||
vcl_deliver | X | X | X | X |
pass | lookup | error | restart | deliver | fetch | pipe | hit_for_pass | |
vcl_recv | X | X | X | X | ||||
vcl_pass | X | X | X | |||||
vcl_lookup | ||||||||
vcl_miss | X | X | X | |||||
vcl_hit | X | X | X | X | ||||
vcl_fetch | X | X | X | X | ||||
vcl_deliver | X | X | X |
请务必阅读 vcl(7) 手册页中 VCL、可用子例程、返回值和对象的完整说明。
让我们通过查看一些示例将所有内容放在一起。
规范化请求的 Host 标头
sub vcl_recv {
if (req.http.host ~ "^www.example.com") {
set req.http.host = "example.com";
}
}
请注意,您可以使用 req.http.host 访问请求的主机标头。通过在 req.http 之后放置标头名称,您可以完全访问所有请求的标头。~ 运算符是匹配运算符。后面跟一个正则表达式。如果匹配,则使用 set 关键字和赋值运算符 (=) 将主机名规范化为简单的“example.com”。规范化主机名的一个非常好的理由是防止 Varnish 缓存重复的响应。Varnish 查看主机名和 URL 以确定是否存在匹配项,因此应尽可能规范化主机名。
这是默认 vcl_recv 子例程的片段
sub vcl_recv {
if (req.request != "GET" && req.request != "HEAD") {
return (pass);
}
return (lookup);
}
这是默认 vcl_recv 子例程的片段。您可以看到,如果它不是 GET 或 HEAD 请求,则 varnish 返回 pass 并且不会缓存响应。如果是 GET 或 HEAD 请求,则会在缓存中查找它。
如果 URL 匹配,则删除请求的 Cookies
sub vcl_recv {
if (req.url ~ "^/images") {
unset req.http.cookie;
}
}
这是 Varnish 网站上的示例。如果 URL 以“/images”开头,它会从请求中删除 cookie。当您回想起 Varnish 不会缓存带有 cookie 的请求时,这是有道理的。通过删除 cookie,您允许 Varnish 缓存响应。
删除图像文件的响应 cookie
sub vcl_fetch {
if (req.url ~ "\.(png|gif|jpg)$") {
unset beresp.http.set-cookie;
set beresp.ttl = 1h;
}
}
这是 Varnish 网站上的另一个示例。在这里,您位于 vcl_fetch 子例程中,该子例程在从后端获取新响应后发生。回想一下,响应保存在 beresp 对象中。请注意,在这里您同时访问请求 (req) 和响应 (beresp)。如果请求是针对图像的,则删除服务器设置的 Set-Cookie 标头,并将缓存响应的 TTL 覆盖为一小时。同样,您这样做是因为 Varnish 不会缓存带有 Set-Cookie 标头的响应。
现在,假设您要向名为 X-Hit 的响应添加标头。对于缓存命中,该值应为 1,对于未命中,该值应为 0。检测命中的最简单方法是从 vcl_hit 子例程中检测。回想一下,vcl_hit 仅在发生缓存命中时执行。理想情况下,您应该从 vcl_hit 中设置响应标头,但查看本文中的表 1,您会看到响应对象(beresp 和 resp)都不可在 vcl_hit 中使用。一种解决方法是在请求中设置临时标头,然后在稍后设置响应标头。让我们看一下如何解决这个问题。
添加 X-Hit 响应标头
sub vcl_hit {
set req.http.tempheader = "1";
}
sub vcl_miss {
set req.http.tempheader = "0";
}
sub vcl_deliver {
set resp.http.X-Hit = "0";
if (req.http.tempheader) {
set resp.http.X-Hit = req.http.tempheader;
unset req.http.tempheader;
}
}
vcl_hit 和 vcl_miss 中的代码很简单——在临时请求标头中设置一个值以指示缓存命中或未命中。有趣的部分在 vcl_deliver 中。首先,我为 X-Hit 设置默认值 0,表示未命中。接下来,我检测请求的 tempheader 是否已设置,如果已设置,则将响应的 X-Hit 标头设置为与先前设置的临时标头匹配。然后我删除 tempheader 以保持整洁,我就完成了。我选择 vcl_deliver 子例程的原因是因为将发送回客户端的响应对象 (resp) 仅在 vcl_deliver 中可用。
让我们探索一个类似的解决方案,但它没有按预期工作。
添加 X-Hit 响应标头——错误的方式
sub vcl_hit {
set req.http.tempheader = "1";
}
sub vcl_miss {
set req.http.tempheader = "0";
}
sub vcl_fetch {
set beresp.http.X-Hit = "0";
if (req.http.tempheader) {
set beresp.http.X-Hit = req.http.tempheader;
unset req.http.tempheader;
}
}
请注意,在 vcl_fetch 中,我现在正在更改后端的响应 (beresp),而不是发送到客户端的最终响应。此代码似乎按预期工作,但它有一个主要错误。发生的情况是,第一个请求是未命中并从后端获取,并且该响应的 X-Hit 设置为“0”,然后将其缓存。后续请求导致缓存命中,并且永远不会进入 vcl_fetch 子例程。结果是,所有缓存命中都继续将 X-Hit 设置为“0”。这些是在使用 Varnish 时要注意的错误类型。
避免这些错误的最简单方法是手头准备好那些参考表;记住每个子例程在 Varnish 工作流程中何时执行,并始终测试结果。
让我们看一下一种简单的方法,告诉 Varnish 缓存所有内容一小时。这仅作为示例显示,不建议用于实际服务器。
缓存所有响应一小时
sub vcl_recv {
return (lookup);
}
sub vcl_fetch {
set beresp.ttl = 1h;
return (deliver);
}
在这里,我用我自己的代码覆盖了两个默认子例程。如果我没有从 vcl_fetch 返回“deliver”,Varnish 仍然会执行其默认 vcl_fetch 子例程来查找返回值,并且这将无法按预期工作。
一旦您让 Varnish 实施您的缓存策略,您应该运行一些基准测试,看看是否有任何改进。我在这里使用的基准测试工具是 Apache 基准测试工具,称为 ab。您可以将此工具作为 Apache Web 服务器的一部分或作为单独的软件包安装——具体取决于您系统的软件包管理器。您可以在手册页或 Apache 网站上阅读有关 ab 可用的各种选项的信息。
在下面的基准测试示例中,我有一个监听端口 80 的库存 Apache 2.2 安装,以及一个监听端口 6081 的 Varnish。我正在测试的页面是我编写的非常基本的 Perl CGI 脚本,它只输出一个单行 HTML 页面。重要的是针对 Web 服务器和 Varnish 对相同的 URL 进行基准测试,以便您可以进行直接比较。我在运行 Apache 和 Varnish 的同一台机器上运行基准测试,以消除网络作为因素。我使用的 ab 选项非常简单。随意尝试不同的 ab 选项,看看会发生什么。
让我们从 1000 个总请求 (-n 1000) 和 1 个并发 (-c 1) 开始。
使用 ab 对 Apache 进行基准测试
ab -c 1 -n 1000 http://localhost/cgi-bin/test

图 4. 来自 ab 命令的输出 (Apache)
使用 ab 对 Varnish 进行基准测试
ab -c 1 -n 1000 http://localhost:6081/cgi-bin/test

图 5. 来自 ab 命令的输出 (Varnish)
如您所见,ab 命令提供了许多有用的输出。我在这里查看的指标是“每个请求的时间”和“每秒请求数” (rps)。您可以看到 Apache 的每个请求时间略高于 1 毫秒 (780 rps),而 Varnish 的每个请求时间为 0.1 毫秒 (7336 rps)——几乎比 Apache 快十倍。这表明 Varnish 更快,至少基于当前的设置和隔离的测试。最好使用各种选项运行 ab 以了解性能——特别是通过更改并发值并查看这对您的系统有何影响。
系统负载和 %iowait系统负载是衡量您的 CPU 上施加了多少负载的指标。作为一般规则,您希望该数字保持在系统上每个 CPU 或内核 1.0 以下。这意味着如果您像我在这里进行基准测试的机器一样拥有四核系统,您希望系统的负载保持在 4.0 以下。
%iowait 是衡量 CPU 时间花费在等待输入/输出上的百分比的指标。较高的 %iowait 表示您的系统受磁盘限制,执行许多磁盘 i/o 操作导致系统速度减慢。例如,如果您的服务器必须为每个请求检索 100 个或更多文件,则可能会导致 %iowait 时间变得非常高,表明磁盘是瓶颈。
目标不仅是缩短响应时间,而且是在尽可能减少对系统资源影响的情况下这样做。让我们比较一下长时间的流量激增如何影响系统资源。衡量系统性能的两个好指标是负载平均值和 %iowait。负载平均值可以在 top 实用程序中看到,%iowait 可以在 iostat 命令中看到。您将需要在长时间负载测试期间密切关注 top 和 iostat,以查看数字如何变化。让我们在单独的终端上启动 top 和 iostat。
以两秒的更新间隔启动 iostat
iostat -c 2
启动 top
/usr/bin/top
现在您已准备好运行基准测试。您希望 ab 运行足够长的时间才能看到对系统性能的影响。这通常意味着从一分钟到十分钟的任何时间。让我们重新运行 ab,总请求数更多,并发性更高。
使用 ab 对 Apache 进行负载测试
ab -c 50 -n 100000 http://localhost/cgi-bin/test

图 6. 流量激增对 Apache 的系统负载影响
使用 ab 对 Varnish 进行负载测试
ab -c 50 -n 1000000 http://localhost:6081/cgi-bin/test

图 7. 流量激增对 Varnish 的系统负载影响
首先让我们比较响应时间。尽管您在截图(在 ab 完成之前拍摄)中看不到它,但 Apache 的每个请求时间为 23 毫秒 (2097 rps),而 Varnish 的每个请求时间为 4 毫秒 (12099 rps)。最显着的差异可以在 top 中的负载平均值中看到。当 Apache 将系统负载一直提高到 12 时,Varnish 将系统负载保持在接近 0 的 0.4。在对 Varnish 进行负载测试之前,我确实必须等待几分钟才能使机器的负载平均值在 Apache 负载测试后恢复下降。最好在主要是空闲的非生产系统上运行这些测试。
尽管每个人的服务器和网站都有不同的要求和配置,但 Varnish 可能会在大幅提高您网站性能的同时,降低服务器的负载。