介绍
智能内容缓存是改善网站访问者体验的最有效方法之一。 缓存或临时存储来自先前请求的内容是在 HTTP 协议中实现的核心内容交付策略的一部分。 整个交付路径中的组件都可以缓存项目以加快后续请求,这取决于为内容声明的缓存策略。
在本指南中,我们将讨论 Web 内容缓存的一些基本概念。 这将主要介绍如何选择缓存策略以确保整个互联网的缓存可以正确处理您的内容。 我们将讨论缓存带来的好处、需要注意的副作用,以及为提供性能和灵活性的最佳组合而采用的不同策略。
什么是缓存?
缓存是存储可重用响应以使后续请求更快的术语。 有许多不同类型的缓存可用,每一种都有自己的特点。 应用程序缓存和内存缓存都因其加速某些响应的能力而广受欢迎。
本指南的重点是 Web 缓存,它是一种不同类型的缓存。 Web 缓存是 HTTP 协议的核心设计功能,旨在最大限度地减少网络流量,同时提高整个系统的感知响应能力。 在从原始服务器到浏览器的内容旅程的每个级别都可以找到缓存。
Web 缓存通过根据特定规则缓存请求的 HTTP 响应来工作。 然后可以从更靠近用户的缓存中完成对缓存内容的后续请求,而不是将请求一直发送回 Web 服务器。
好处
有效的缓存有助于内容消费者和内容提供者。 缓存为内容交付带来的一些好处是:
- 降低网络成本:内容可以缓存在内容消费者和内容来源之间的网络路径中的各个点。 当内容缓存在更靠近消费者的位置时,请求不会导致超出缓存的额外网络活动。
- 改进的响应能力:缓存可以更快地检索内容,因为不需要整个网络往返。 靠近用户维护的缓存,如浏览器缓存,可以使这种检索几乎是即时的。
- 在相同硬件上提高性能:对于内容来源的服务器,通过允许积极缓存,可以从相同硬件中榨取更多性能。 内容所有者可以利用交付路径上的强大服务器来首当其冲地承受某些内容负载。
- 网络中断期间内容的可用性:通过某些策略,即使原始服务器可能在短时间内不可用,缓存也可用于向最终用户提供内容。
术语
在处理缓存时,您可能会遇到一些您可能不熟悉的术语。 一些较常见的如下:
- 源服务器:源服务器是内容的原始位置。 如果您作为 Web 服务器管理员,这就是您控制的机器。 它负责为请求路由中无法从缓存中检索到的任何内容提供服务,并负责为所有内容设置缓存策略。
- 缓存命中率:缓存的有效性是根据其缓存命中率或命中率来衡量的。 这是能够从缓存中检索到的请求与发出的总请求的比率。 高缓存命中率意味着能够从缓存中检索到高百分比的内容。 这通常是大多数管理员想要的结果。
- 新鲜度:新鲜度是一个术语,用于描述缓存中的项目是否仍被视为提供给客户端的候选对象。 只有在缓存策略指定的新鲜时间范围内,缓存中的内容才会用于响应。
- 过期内容:缓存中的项目根据缓存策略中的缓存新鲜度设置过期。 过期的内容是“陈旧的”。 通常,过期的内容不能用于响应客户端请求。 必须重新联系原始服务器以检索新内容或至少验证缓存的内容仍然准确。
- Validation:可以验证缓存中的陈旧项目以刷新它们的到期时间。 验证涉及与原始服务器签入以查看缓存的内容是否仍代表最新版本的项目。
- Invalidation:失效是在指定过期日期之前从缓存中删除内容的过程。 如果原始服务器上的项目已更改并且缓存中的过期项目会给客户端带来重大问题,则这是必要的。
还有很多其他的缓存术语,但上面的那些应该可以帮助您入门。
什么可以缓存?
某些内容比其他内容更容易缓存。 大多数网站的一些对缓存非常友好的内容是:
- 标志和品牌形象
- 一般不旋转的图像(例如导航图标)
- 样式表
- 通用 Javascript 文件
- 可下载的内容
- 媒体文件
这些往往很少更改,因此它们可以从缓存更长的时间中受益。
在缓存中必须小心的一些项目是:
- HTML 页面
- 旋转图像
- 经常修改的 Javascript 和 CSS
- 使用身份验证 cookie 请求的内容
一些几乎不应该被缓存的项目是:
- 与敏感数据(银行信息等)相关的资产
- 用户特定且经常更改的内容
除了上述一般规则之外,还可以指定允许您适当缓存不同类型内容的策略。 例如,如果经过身份验证的用户都看到您网站的相同视图,则可以在任何地方缓存该视图。 如果经过身份验证的用户看到网站的用户敏感视图将在一段时间内有效,您可以告诉用户的浏览器进行缓存,但告诉任何中间缓存不要存储该视图。
缓存 Web 内容的位置
内容可以在整个交付链的许多不同点缓存:
- 浏览器缓存:Web浏览器本身维护一个小缓存。 通常,浏览器会设置一个策略来指示要缓存的最重要的项目。 这可能是用户特定的内容或被认为下载成本高且可能再次被请求的内容。
- 中间缓存代理:客户端和基础设施之间的任何服务器都可以根据需要缓存某些内容。 这些缓存可能由 ISP 或其他独立方维护。
- 反向缓存:您的服务器基础架构可以为后端服务实现自己的缓存。 这样,可以从接触点提供内容,而不是针对每个请求访问后端服务器。
这些位置中的每一个都可以并且经常根据它们自己的缓存策略和在内容源处设置的策略来缓存项目。
缓存标头
缓存策略取决于两个不同的因素。 缓存实体本身决定是否缓存可接受的内容。 它可以决定缓存的数量少于允许缓存的数量,但永远不会多。
大多数缓存行为由内容所有者设置的缓存策略决定。 这些策略主要通过使用特定的 HTTP 标头来阐明。
通过 HTTP 协议的各种迭代,出现了一些不同的以缓存为中心的标头,其复杂程度各不相同。 您可能仍然需要注意的内容如下:
- Expires:
Expires
标头非常简单,尽管范围相当有限。 基本上,它设置了将来内容到期的时间。 此时,对相同内容的任何请求都必须返回到源服务器。 此标头可能最好仅用作后备。 - Cache-Control:这是
Expires
标头的更现代的替代品。 它得到很好的支持并实现了更灵活的设计。 在几乎所有情况下,这都比Expires
更可取,但同时设置这两个值可能没有坏处。 稍后我们将讨论您可以使用Cache-Control
设置的选项的细节。 - Etag:
Etag
标头用于缓存验证。 当最初提供内容时,源可以为项目提供唯一的Etag
。 当缓存需要在过期时验证它现有的内容时,它可以发回它对内容的Etag
。 源端要么告诉缓存内容是相同的,要么发送更新的内容(使用新的Etag
)。 - Last-Modified:此标头指定上次修改项目的时间。 这可以用作验证策略的一部分,以确保内容新鲜。
- Content-Length:虽然没有特别涉及缓存,但在定义缓存策略时设置
Content-Length
标头很重要。 如果某些软件事先不知道需要为其保留空间的内容的大小,它将拒绝缓存内容。 - Vary:缓存通常使用请求的主机和资源路径作为存储缓存项的键。
Vary
标头可用于告诉缓存在确定请求是否针对同一项目时注意附加标头。 这最常用于通过Accept-Encoding
标头告诉缓存键,以便缓存知道区分压缩和未压缩的内容。
关于 Vary Header 的旁白
Vary
标头使您能够以稀释缓存中的条目为代价存储相同内容的不同版本。
在 Accept-Encoding
的情况下,设置 Vary
标头允许在压缩和未压缩内容之间进行关键区分。 这对于将这些项目正确地提供给无法处理压缩内容的浏览器是必需的,并且是提供基本可用性所必需的。 告诉您 Accept-Encoding
可能是 Vary
的一个很好的候选者的一个特征是它只有两个或三个可能的值。
User-Agent
之类的项目乍一看似乎是区分移动浏览器和桌面浏览器以服务不同版本网站的好方法。 但是,由于 User-Agent
字符串是非标准的,结果可能是中间缓存上相同内容的多个版本,缓存命中率非常低。 应谨慎使用 Vary
标头,尤其是当您无法规范您控制的中间缓存中的请求时(例如,如果您利用内容交付网络,这可能是可能的)。
缓存控制标志如何影响缓存
上面,我们提到了 Cache-Control
标头如何用于现代缓存策略规范。 可以使用此标头设置许多不同的策略指令,多个指令用逗号分隔。
您可以使用一些 Cache-Control
选项来规定内容的缓存策略:
- no-cache:该指令指定任何缓存的内容在提供给客户端之前必须在每个请求上重新验证。 实际上,这会立即将内容标记为过时,但允许它使用重新验证技术来避免再次重新下载整个项目。
- no-store:该指令表示内容不能以任何方式缓存。 如果响应代表敏感数据,则适合设置。
- public:这会将内容标记为公共,这意味着它可以被浏览器和任何中间缓存缓存。 对于使用 HTTP 身份验证的请求,响应默认标记为
private
。 此标头会覆盖该设置。 - private:这会将内容标记为
private
。 私有内容可以由用户的浏览器存储,但必须而不是被任何中间方缓存。 这通常用于特定于用户的数据。 - max-age:此设置配置内容在必须重新验证或从源服务器重新下载内容之前可以缓存的最大期限。 本质上,这取代了现代浏览的
Expires
标头,是确定一段内容新鲜度的基础。 此选项以秒为单位取值,最长有效新鲜时间为一年(31536000 秒)。 - s-maxage:这与
max-age
设置非常相似,因为它表示内容可以缓存的时间量。 不同之处在于此选项仅适用于中间缓存。 将其与上述相结合允许更灵活的策略构建。 - must-revalidate:表示必须严格遵守
max-age
、s-maxage
或Expires
头信息所指示的新鲜度信息。 在任何情况下都不能提供过时的内容。 这可以防止在网络中断和类似情况下使用缓存的内容。 - proxy-revalidate:这与上述设置的操作相同,但仅适用于中间代理。 在这种情况下,用户的浏览器可能被用于在网络中断的情况下提供陈旧的内容,但中间缓存不能用于此目的。
- no-transform:此选项告诉缓存在任何情况下都不允许出于性能原因修改接收到的内容。 这意味着,例如,缓存无法发送它没有从原始服务器接收到的压缩内容的压缩版本,并且是不允许的。
这些可以以不同的方式组合以实现各种缓存行为。 一些互斥的值是:
no-cache
、no-store
,以及由缺少任何一个表示的常规缓存行为public
和private
如果两者都存在,则 no-store
选项将取代 no-cache
选项。 对于未经身份验证的请求的响应,隐含 public
。 对于经过身份验证的请求的响应,private
是隐含的。 这些可以通过在 Cache-Control
标头中包含相反的选项来覆盖。
制定缓存策略
在一个完美的世界里,一切都可以被积极缓存,你的服务器只会偶尔被联系以验证内容。 虽然这在实践中并不经常发生,因此您应该尝试设置一些合理的缓存策略,旨在在实现长期缓存和响应不断变化的站点的需求之间取得平衡。
常见问题
由于内容的生成方式(每个用户动态生成)或内容的性质(例如敏感的银行信息),在许多情况下不能或不应该实现缓存。 许多管理员在设置缓存时面临的另一个问题是,即使新版本已经发布,旧版本的内容仍然存在,还没有过时。
这些都是经常遇到的问题,可能会对缓存性能和您所服务内容的准确性产生严重影响。 但是,我们可以通过开发预测这些问题的缓存策略来缓解这些问题。
一般建议
虽然您的情况将决定您使用的缓存策略,但以下建议可以帮助指导您做出一些合理的决定。
在担心您使用的特定标头之前,您可以采取某些步骤来提高缓存命中率。 一些想法是:
- 为图像、CSS 和共享内容建立特定目录:将内容放置到专用目录中,您可以轻松地从站点上的任何页面引用它们。
- 使用相同的 URL 来引用相同的项目:由于缓存了主机和请求内容的路径的密钥,因此请确保您在所有页面上以相同的方式引用您的内容。 先前的建议使这变得容易得多。
- 尽可能使用 CSS 图像精灵:图标和导航等项目的 CSS 图像精灵减少了呈现您的网站所需的往返次数,并允许您的网站长时间缓存单个精灵。
- 尽可能在本地托管脚本和外部资源:如果您使用 javascript 脚本和其他外部资源,如果上游未提供正确的标头,请考虑将这些资源托管在您自己的服务器上。 请注意,您必须了解对上游资源所做的任何更新,以便您可以更新本地副本。
- 指纹缓存项目:对于CSS和Javascript文件等静态内容,可能适合对每个项目进行指纹识别。 这意味着为文件名添加一个唯一标识符(通常是文件的哈希),这样如果资源被修改,就可以请求新的资源名称,从而使请求正确绕过缓存。 有多种工具可以帮助创建指纹并修改 HTML 文档中对指纹的引用。
在为不同的项目选择正确的标题方面,以下内容可以作为一般参考:
- 允许所有缓存存储通用资产:静态内容和非用户特定的内容可以而且应该在交付链中的所有点进行缓存。 这将允许中间缓存响应多个用户的内容。
- 允许浏览器缓存用户特定的资产:对于每个用户的内容,允许在用户的浏览器中缓存通常是可以接受和有用的。 虽然此内容不适合缓存在任何中间缓存代理上,但浏览器中的缓存将允许用户在后续访问期间即时检索。
- 对重要的时间敏感内容进行例外处理:如果您有时间敏感的内容,请对上述规则进行例外处理,以便在紧急情况下不提供过时的内容。 例如,如果您的网站有一个购物车,它应该立即反映购物车中的项目。 根据内容的性质,可以在
Cache-Control
标头中设置no-cache
或no-store
选项来实现此目的。 - 始终提供验证器:验证器允许刷新陈旧的内容,而无需再次下载整个资源。 设置
Etag
和Last-Modified
标头允许缓存验证其内容并在其未在源处修改时重新提供它,从而进一步减少负载。 - 为支持内容设置较长的新鲜时间:为了有效地利用缓存,被请求作为支持内容来满足请求的元素通常应该具有较长的新鲜度设置。 这通常适用于拉入以呈现用户请求的 HTML 页面的图像和 CSS 等项目。 设置延长的新鲜时间,结合指纹识别,允许缓存长时间存储这些资源。 如果资产发生变化,修改后的指纹将使缓存项失效,并触发新内容的下载。 在那之前,支持项目可以被缓存到很远的将来。
- 为父内容设置较短的新鲜时间:为了使上述方案起作用,包含的项目必须具有相对较短的新鲜时间或者可能根本不被缓存。 这通常是调用其他辅助内容的 HTML 页面。 HTML 本身将被频繁下载,使其能够快速响应更改。 然后可以积极缓存支持内容。
关键是要取得平衡,在可能的情况下支持积极缓存,同时在将来进行更改时留下使条目无效的机会。 您的网站可能会有以下组合:
- 积极缓存的项目
- 具有较短新鲜时间和重新验证能力的缓存项目
- 根本不应该缓存的项目
目标是在可能的情况下将内容移至第一类,同时保持可接受的准确性水平。
结论
花时间确保您的站点具有适当的缓存策略可能会对您的站点产生重大影响。 缓存允许您减少与重复提供相同内容相关的带宽成本。 您的服务器也将能够使用相同的硬件处理更多的流量。 也许最重要的是,客户将在您的网站上获得更快的体验,这可能会导致他们更频繁地返回。 虽然有效的 Web 缓存不是灵丹妙药,但设置适当的缓存策略可以让您以最少的工作获得可观的收益。