如何使用 Varnish 提升服务器性能
Varnish Cache 是由丹麦顾问和 FreeBSD 核心开发人员 Poul-Henning Kamp 以及挪威 Linpro AS 的其他开发人员开发的 HTTP 加速器和反向代理。 它于 2006 年发布。
据一家专注于网络性能的公司 Pingdom.com 称,在 2012 年,Varnish 已经因其加速网络交付的能力而在世界顶级网站中享有盛名,并被 Wired、SlideShare、Zappos、SoundCloud 等网站使用, Weather.com、Business Insider、Answers.com、Urban Dictionary、MacRumors、DynDNS、OpenDNS、Lonely Planet、Technorati、ThinkGeek 和 Economist.com。
它是根据两条款 BSD 许可获得许可的。 Varnish 有一个高级层 Varnish Plus,专注于企业客户,提供一些额外的功能、模块和支持。
尽管还有其他解决方案也很出色,但 Varnish 仍然是一个首选解决方案,它可以显着提高网站速度,减少 Web 应用程序服务器 CPU 的压力,甚至可以作为抵御 DDoS 攻击的保护层。 KeyCDN 建议将其部署在原始服务器堆栈上。
如果网站要求更高,Varnish 可以位于专用机器上,并确保原始服务器不受请求泛滥的影响。
在撰写本文时(2017 年 11 月),Varnish 的版本为 5.2。
怎么运行的
缓存通常通过将应用程序的预先计算的输出保存在内存或磁盘上来工作,这样就不必在每个请求上一遍又一遍地计算昂贵的计算。 Web 缓存可以在客户端(浏览器缓存),也可以在服务器上。 清漆属于第二类。 它通常配置为在标准 HTTP 端口 (80) 上侦听请求,然后将请求的资源提供给网站访问者。
第一次请求某个 URL 和路径时,Varnish 必须从源服务器请求它才能将其提供给访问者。 这称为 CACHE MISS,可以在 HTTP 响应标头中读取,具体取决于 Varnish 设置。
根据文档,
当一个对象,任何类型的内容,如图像或页面,没有存储在缓存中时,我们就会遇到通常所说的缓存未命中,在这种情况下,Varnish 将从 Web 服务器获取内容,存储它并向用户提供一个副本并将其保留在缓存中以响应未来的请求。
当特定的 URL 或资源被 Varnish 缓存并存储在内存中时,可以直接从服务器 RAM 中提供服务; 不需要每次都计算。 Varnish 将在几微秒内开始提供 CACHE HIT。
这意味着我们的原始服务器或我们的 Web 应用程序(包括其数据库)都不会被未来的请求所触及。 他们甚至不会意识到缓存 URL 上加载的请求。
源服务器——或者多个服务器,如果我们使用 Varnish 作为负载均衡器的话——被配置为监听一些非标准端口,比如 8888,并且 Varnish 知道它们的地址和端口。
清漆特性
清漆是螺纹的。 据报道,Varnish 能够在单个实例上每秒处理超过 200,000 个请求。 如果配置正确,您的 Web 应用程序的唯一瓶颈将是网络吞吐量和 RAM 量。 (这应该不是一个不合理的要求,因为它只需要将计算的网页保存在内存中,所以对于大多数网站来说,几千兆字节就足够了。)
Varnish 可以通过 VMODS 进行扩展。 这些模块可以使用标准 C 库并扩展 Varnish 功能。 这里列出了社区贡献的 VMODS。 它们的范围从标头操作到 Lua 脚本、请求限制、身份验证等。
Varnish 有自己的领域特定语言 VCL。 VCL 提供全面的可配置性。 对于像 Varnish 这样的全页缓存服务器,有很多复杂的问题需要解决。
当我们使用 GET 查询参数缓存包含数十个或数百个页面和路径的动态网站时,我们希望从缓存中排除其中一些,或者设置不同的缓存过期规则。 有时我们想要缓存某些 Ajax 请求,或者将它们从缓存中排除。 这因项目而异,无法提前定制。
有时我们希望 Varnish 根据请求标头来决定如何处理请求。 有时我们会希望使用特定的 cookie 集将请求直接传递到后端。
引用清漆书,
VCL 提供的子例程允许您影响执行链中几乎任何位置的任何单个请求的处理。
清除缓存通常需要动态完成——通过发布文章或更新网站触发。 清除也需要尽可能以原子方式完成——这意味着它应该针对尽可能小的范围,比如单个资源或路径。
这意味着需要定义特定规则,并牢记它们的优先顺序。 一些示例可以在 Varnish 书中找到(可以在线阅读或作为可下载的 PDF)。
Varnish 有一套用于监视和管理服务器的工具:
有 varnishtop
,这让我们可以监控请求的 URL 及其频率。
varnishncsa
可用于打印 Varnish 共享内存日志 (VSL):它转储指向特定域和子域的所有内容。
varnishhist
读取 VSL 并呈现实时直方图,显示最近请求数的分布情况,概述服务器和后端性能。
varnishtest
用于测试VCL配置文件和开发VMODS。
varnishstat
显示有关我们的 varnishd 实例的统计信息:
varnishlog
用于获取有关特定客户端和请求的数据。
Varnish Software 提供一组商业的付费解决方案,这些解决方案要么构建在 Varnish 缓存之上,要么扩展其使用并帮助监控和管理:Varnish Api Engine、Varnish Extend、Akamai Connector for Varnish、Varnish Administration Console (VAC) 和 Varnish自定义统计信息 (VCS)。
安装清漆
Varnish 文档涵盖了在各种系统上的安装。 在这篇文章中,我们将使用 Ubuntu 16.04 LTS。
Packagecloud.io 有更新 Ubuntu 存储库和安装 Varnish 版本 5 的说明:
curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y apt-transport-https
然后我们将以下行添加到新创建的文件中 /etc/apt/sources.list.d/varnishcache_varnish5.list
:
deb https://packagecloud.io/varnishcache/varnish5/ubuntu/ xenial main
deb-src https://packagecloud.io/varnishcache/varnish5/ubuntu/ xenial main
然后我们运行:
sudo apt-get update
sudo apt-get install varnish
我们可以测试在 Nginx 上运行的全新 WordPress 安装。 首先,我们将 Nginx 的默认监听端口从 80 更改为 8080——这是 Varnish 期望后端运行的端口——通过在服务器子句内的 Nginx 虚拟主机中添加以下行:
server {
listen 127.0.0.1:8080 default_server;
listen [::]:8080 default_server;
然后我们配置清漆:我们编辑 /etc/default/varnish
,将端口 6081 替换为 80(默认 Web 端口):
DAEMON_OPTS="-a :80
-T localhost:6082
-f /etc/varnish/default.vcl
-S /etc/varnish/secret
-s malloc,256m"
我们也需要改变 /lib/systemd/system/varnish.service
,进行相同的替换:
[Service]
Type=simple
LimitNOFILE=131072
LimitMEMLOCK=82000
ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m
ExecReload=/usr/share/varnish/reload-vcl
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
然后我们重启 Nginx 和 Varnish:
sudo service nginx restart
sudo /etc/init.d/varnish restart
警告:由于一些特殊性,Varnish 通常必须重新启动——或者以这种方式启动,而不是 service varnish start
——为了读取我们编辑的所有配置文件。
我们使用 Locust 和 Pingdom 工具测试了网站速度和响应能力。
一旦缓存预热,尽管 Nginx 以其速度着称,但差异是惊人的:每秒平均请求数增加了三到四倍,并且响应时间大大减少。 由于网络延迟,加载时间有点长,因为我们从欧洲的工作站测试了托管在加利福尼亚的网站。
Nginx 的 Locust 结果:
Nginx + Varnish 的 Locust 结果:
Pingdom 结果也不错。
Nginx 堆栈的 Pingdom 结果,从加利福尼亚测试:
加州 Nginx + Varnish 的 Pingdom 结果:
另请注意每个案例的 TTFB。
单独使用 Nginx:
Nginx +清漆:
即使我们忽略粉红色的部分,也就是 DNS 查找,仍然存在明显的差异。
设置简单
Varnish 不关心端口 8080 上正在监听什么(如果需要,我们也可以更改此默认端口)。 这意味着设置 Apache 或其他一些应用程序服务器应该同样简单:我们需要做的就是将它们配置为侦听端口 8080 而不是 80。
使用 NodeJS 设置 Varnish
在我们已经安装了 Varnish 的现有服务器上,设置一个 hello-world Node 应用程序同样简单。 我们安装了 nodejs
和 npm
打包并将 NodeJS 链接到 Node:
ln -s /usr/bin/nodejs /usr/bin/node
然后我们创建了一个简单的监听 8080 端口的 node hello-world 程序:
#!/usr/bin/env nodejs
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello Worldn');
}).listen(8080, 'localhost');
console.log('Server running at http://localhost:8080/');
然后我们安装了 Node 的包管理器 PM2,以便能够守护我们的应用程序:
sudo npm install -g pm2
pm2 start index.js
aAnd voila — 我们的 Node 应用程序由 Varnish 提供服务:
其他提示
为了能够控制我们的请求是否被缓存在我们的浏览器检查器中,我们应该将以下代码片段添加到我们的 Varnish 配置文件中,进入 sub vcl_deliver
堵塞:
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
}
然后我们可以在响应头中看到 HIT 或 MISS 的反馈:
还有一个警告:Varnish(或者至少是开源版本)不支持 SSL,其创建者 Poul-Henning Kamp(他并不羞于表达自己的意见)再次重申了这一点。 所以当你需要使用 Varnish 和 HTTPS 时,考虑在它前面使用另一个代理来终止 SSL——比如 haproxy,或者 Varnish 自己的 hitch。
或者,如果这太复杂了,只需使用 Nginx 和 FastCGI 缓存。
结论
在本文中,我们试图对 Varnish Cache 进行简要介绍,而不会深入探讨其设置、监控和管理。
调整服务器性能本身就是一门科学,要介绍完整的用例和设置范围需要另一篇文章。 我将在另一篇文章中更深入地探讨这个主题,敬请期待下一期,我将在真正的应用程序前面添加 Varnish。