首先,我们应该区分在正常 Web 系统中进行的两种不同类型的缓存:HTTP 缓存和服务器端缓存。
HTTP 缓存由 HTTP 标头控制,特别是正如您所指出的ETag
以及各种到期机制(包括Expires
的各个方面Cache-Control
)。这一切都在RFC 2616 (HTTP) 第 13 节中进行了介绍,并允许 HTTP缓存返回对来自客户端的 HTTP 请求的响应,而无需返回到源服务器. 实际上,在某些情况下,HTTP 缓存机制允许客户端和服务器之间的另一台机器充当服务器。这实际上就是 varnish 正在做的事情,我们马上就会看到;许多人熟悉的另一个常见用途是当 ISP 在其网络中提供 HTTP 缓存时,通常可以比其网络外的原始服务器更快地响应其订阅者(从而提高感知性能)。
服务器端缓存包括数据库缓存、片段和页面缓存,这些实际上都是 Web 服务器避免执行一些昂贵操作(例如,数据库查询或渲染模板的特定部分)的方式,只需执行一次即可将结果保存在缓存中一段时间。
我之前说过 varnish 是一种 HTTP 缓存,这意味着它可以立即比提供静态文件的 Web 服务器更高效。考虑 Web 服务器必须做什么:
- 解析 HTTP 请求
- 将 URI(以及任何相关的请求标头,例如
Accept-Encoding
)映射到文件
- 提取有关文件的信息以在响应中构建 HTTP 标头;这些被称为实体标头(RFC 2616 第 7.1 节,其中包括HTTP 缓存中使用的 、 和
Content-Length
标Content-Type
头等内容)Expires
Last-Modified
- 找出需要哪些额外的响应标头(RFC 2616 第 6.2 节;这些包括
ETag
和Vary
,都是 HTTP 缓存的重要部分)和一般标头字段(RFC 2616 第 4.5 节)
- 将 HTTP 状态行和标头写入网络
- 将文件内容写入网络
相比之下,varnish 是所有这些的上游,所以它所要做的就是:
- 解析 HTTP 请求
- 将 URI(和任何相关的请求标头)映射到其内部缓存中的条目
- 查看是否有条目;如果有,将其写入网络;HTTP 标头将存储在缓存中
如果没有条目,varnish 必须做更多的工作:
- 连接到它后面的 Web 服务器,该服务器将运行第一个列表中的所有步骤 1-6 以生成响应
- 将响应写入网络,包括所有 HTTP 标头
- 将响应存储在其缓存中
特别是因为 HTTP 标头和实体主体(整个响应)可以由 varnish 缓存,如果它可以从缓存中提供服务,那么它要做的工作就更少了。当您开始在服务器中动态生成响应时,差异会变得更加明显:假设您有一个页面需要 5 秒才能生成,但对于访问您网站的每个人来说都是一样的,varnish 应该能够在缓存中的大多数毫秒(加上通过网络获得对 HTTP 客户端的响应所需的任何时间),并且具有简洁的机制(宽限期),因此它可以在访问后端服务器一次刷新的同时继续执行此操作页面的缓存版本。
当然,您可以引入服务器端缓存来提高 Web 服务器处理请求的速度,但如果您有响应,您可以缓存在 varnish 中,这样做通常会更快。(有很多东西很难在 varnish 中缓存,特别是如果您使用 cookie 或页面会根据正在查看的用户而变化。虽然在这些情况下可以继续使用 varnish,除非您需要非常棒的速度,据我所知,大多数人在使用清漆之前开始使用服务器端缓存和其他技术优化这些案例。)
(请注意,varnish 还可以编辑标题以及确实进出缓存的数据,这使事情变得复杂。但要点仍然存在,即使在动态编辑内容时,varnish 也可以非常快。)