内容分发网络 (CDN)

使用内容分发网络提升性能。

凯蒂·亨佩纽斯
Katie Hempenius

内容分发网络 (CDN) 使用分布式服务器网络向用户分发资源,从而提升网站性能。由于 CDN 可以减少服务器负载,因此可以降低服务器成本,并且非常适合处理流量高峰。本文介绍了 CDN 的工作原理,并针对如何选择、配置和优化 CDN 设置提供了与平台无关的指导。

概览

内容分发网络由为快速向用户分发内容而优化的服务器网络组成。虽然 CDN 无疑以提供缓存内容而闻名,但 CDN 也可以改善无法缓存内容的分发。一般来说, CDN 分发的网站越多越好。

概括来讲,CDN 的性能优势源于几个原则:CDN 服务器比源服务器离用户更近,因此具有较短的往返时间 (RTT) 延迟时间;网络优化使 CDN 能够比从源服务器“直接”加载内容时更快地传送内容;最后,CDN 缓存消除了将请求发送到源服务器的需求。

资源分发

虽然使用 CDN 分发资源(即使是无法缓存的资源)可能看起来并不直观,但通常比让用户从您的服务器“直接”加载资源要快。

使用 CDN 从源站分发资源时,客户端和附近的 CDN 服务器之间会建立新的连接。该过程的剩余部分(换言之,CDN 服务器和源站之间的数据传输)通过 CDN 网络进行,这通常包括与源站的现有持久连接。这样做的好处有两个:尽可能在靠近用户的位置终止新连接,从而避免不必要的连接设置成本(建立新连接成本高昂,需要多次往返);使用预热连接可让数据以尽可能高的吞吐量立即传输。

使用 CDN 与不使用 CDN 的连接设置对比

有些 CDN 通过分布在互联网上的多个 CDN 服务器将流量路由至源,从而进一步改进了此问题。CDN 服务器之间的连接是通过可靠且高度优化的路由进行的,而不是通过边界网关协议 (BGP) 确定的路由。虽然 BGP 实际上是互联网的路由协议,但其路由决策并不总是以性能为导向。因此,与 CDN 服务器之间经微调的路由相比,由 BGP 确定的路由的性能可能较低。

使用 CDN 与不使用 CDN 的连接设置对比

缓存

通过在 CDN 服务器上缓存资源,请求不必一直传输到源站即可提供资源。因此,资源的分发速度会更快;这也降低了源服务器的负载。

将资源添加到缓存中

填充 CDN 缓存的最常用方法是让 CDN 根据需要“拉取”资源 - 这称为“源提取”。首次从缓存中请求特定资源时,CDN 会向源服务器请求该资源并缓存响应。通过这种方式,缓存的内容会随着请求其他未缓存资源而逐渐累积。

从缓存中移除资源

CDN 使用缓存逐出来定期从缓存中移除无用的资源。此外,网站所有者还可以使用完全清除功能来明确移除资源。

  • 缓存逐出

    缓存的存储空间容量有限。当缓存即将用尽容量时,它会移除最近未被访问或占用大量空间的资源,为新资源腾出空间。此过程称为缓存逐出。将资源从一个缓存中逐出并不一定意味着它已经从 CDN 网络中的所有缓存中逐出。

  • 清除

    清除(也称为“缓存失效”)是一种从 CDN 的缓存中移除资源而无需等待其过期或被逐出的机制。它通常通过 API 执行。在需要撤消内容(例如,更正拼写错误、定价错误或错误的新闻报道)的情况下,完全清除操作就至关重要。除此之外,它还可以在网站的缓存策略中发挥重要作用。

    如果 CDN 支持近乎即时完全清除,则可以将完全清除用作一种管理动态内容缓存的机制:使用长 TTL 缓存动态内容,然后在资源更新时完全清除。采用这种方式,即使未提前知道动态资源的更改时间,也可以最大限度地延长该资源的缓存时长。此技术有时称为“保留保持缓存”。

    在大规模执行完全清除时,通常与称为“缓存标记”或“代理缓存键”的概念结合使用。此机制允许网站所有者将一个或多个其他标识符(有时称为“标记”)与缓存资源相关联。然后,您可以使用这些代码执行高度精细的完全清除。例如,您可以向包含网站页脚的所有资源(例如 /about/blog)添加“footer”标记。页脚更新后,指示您的 CDN 完全清除与“footer”标记关联的所有资源。

可缓存的资源

资源是否应缓存以及如何缓存取决于该资源是公开还是私有、静态还是动态。

私有资源和公共资源
  • 不公开资源

    私有资源包含面向单个用户的数据,因此不应由 CDN 缓存。私有资源由 Cache-Control: private 标头指示。

  • 公共资源

    公共资源不包含用户特定信息,因此可由 CDN 缓存。如果资源没有 Cache-Control: no-storeCache-Control: private 标头,则会被 CDN 视为可缓存。公共资源的缓存时间取决于资源的变化频率。

动态内容和静态内容
  • 动态内容

    动态内容是指经常变化的内容。API 响应和商店首页都是此类内容类型的示例。不过,此内容频繁更改并不一定会导致系统无法对其进行缓存。在流量较大的时段,将这些响应缓存极短时间(例如 5 秒)可以显著减少源服务器的负载,同时对数据新鲜度的影响微乎其微。

  • 静态内容

    静态内容很少更改(如果有的话)。图片、视频和带版本号的库通常是这种内容类型的示例。由于静态内容不会改变,因此应缓存较长的存留时间 (TTL),例如 6 个月或 1 年。

选择 CDN

选择 CDN 时,性能通常是首要考虑因素。但是,在选择 CDN 时,CDN 提供的其他功能(例如安全和分析功能)以及 CDN 的价格、支持和初始配置都需要考虑。

性能

概括来讲,CDN 的性能策略可以在最大限度缩短延迟时间和提高缓存命中率之间的权衡考虑。具有许多入网点 (PoP) 的 CDN 可以提供更低的延迟,但由于流量被拆分到更多缓存中,因此缓存命中率可能会降低。相反,具有较少 PoP 的 CDN 的地理位置可能离用户更远,但可以实现更高的缓存命中率。

基于这种权衡,一些 CDN 使用分层方式进行缓存:位于用户附近的 PoP(也称为“边缘缓存”)会通过具有较高缓存命中率的中央 PoP 补充。当边缘缓存找不到某个资源时,它会查找该资源的中央 PoP。这种方法以稍长的延迟换取更高的从 CDN 缓存传送资源的可能性,但不一定是边缘缓存提供资源。

最大限度缩短延迟时间和提高缓存命中率之间的权衡取舍多种选择。没有哪一种特定方法在所有地方都更好;但是,根据您网站的性质及其用户群,您可能会发现其中某一种方法能显著改善效果。

另外值得注意的是,CDN 性能可能会因地理位置、一天中的时段甚至时事不同而有很大差异。虽然自行研究 CDN 的性能始终是个好主意,但是很难预测从 CDN 获得的确切性能。

对 Largest Contentful Paint (LCP) 的影响

如本文前面所述,CDN 的主要目的是将资源分布到在地理位置上更靠近用户的服务器,从而减少延迟时间。因此,CDN 的主要优势在于提高加载性能。特别是,将 CDN 引入网站的服务器端架构后,资源的首字节时间 (TTFB) 可以得到显著改善。

虽然 TTFB 不是以用户为中心的性能指标,但它诊断 Largest Contentful Paint (LCP) 相关问题的重要指标,LCP 是一种以用户为中心的指标。

CDN 在改进 LCP 方面尤其有效,因为它们可以改进文档分发(通过减少连接设置和缓存文档中的 TTFB)和改进渲染 LCP 元素所需任何静态资源的分发。

其他功能

除核心 CDN 产品外,CDN 通常还提供各种功能。提供的常见功能包括:负载均衡、映像优化、视频串流、边缘计算和安全产品。

如何设置和配置 CDN

理想情况下,您应使用 CDN 为整个网站提供内容。大体上讲,设置过程包括向 CDN 提供商进行注册,然后更新您的 CNAME DNS 记录,使其指向该 CDN 提供商。例如,www.example.com 的 CNAME 记录可能指向 example.my-cdn.com。由于此 DNS 更改,流向您网站的流量将通过 CDN 进行路由。

如果无法使用 CDN 提供所有资源,您可以将 CDN 配置为仅提供部分资源,例如,仅提供静态资源。为此,您可以创建单独的 CNAME 记录,该记录将仅用于应由 CDN 提供的资源。例如,您可以创建一条指向 example.my-cdn.comstatic.example.com CNAME 记录。您还需要重写 CDN 提供的资源的网址,以指向您创建的 static.example.com 子网域。

虽然您的 CDN 将在此时设置完毕,但配置时可能会出现效率低下的情况。本文的以下两部分将介绍如何通过提高缓存命中率和启用性能功能来充分利用 CDN。

提高缓存命中率

有效的 CDN 设置将从缓存中处理尽可能多的资源。这通常通过缓存命中率 (CHR) 来衡量。缓存命中率是指给定时间间隔内的缓存命中数除以总请求数所得的值。

新初始化的缓存的 CHR 为 0,但随着缓存中不断填充资源,该值会增加。对大多数网站而言,CHR 为 90% 是一个不错的目标。您的 CDN 提供商应为您提供有关 CHR 的分析和报告。

优化 CHR 时,要验证的首要事项是,所有可缓存的资源在缓存和缓存时均正确时长。这是一项简单的评估,所有网站都应进行。

一般来说,下一级别的 CHR 优化是微调 CDN 设置,以确保逻辑上等效的服务器响应不会单独缓存。受查询参数、Cookie 和请求标头等因素对缓存的影响,经常会造成效率低下。

初步审核

大多数 CDN 都会提供缓存分析。此外,WebPageTestLighthouse 等工具也可用来快速验证网页的所有静态资源是否缓存了正确时长。这是通过检查每个资源的 HTTP 缓存标头来实现的。使用适当的最长存留时间 (TTL) 缓存资源,可避免日后出现不必要的源站提取,从而增加 CHR。

通常,您至少需要设置以下标头中的一个,CDN 才能缓存资源:

  • Cache-Control: max-age=
  • Cache-Control: s-maxage=
  • Expires

此外,虽然这不会影响 CDN 是否缓存资源或缓存方式,但最好同时设置 Cache-Control: immutable 指令。Cache-Control: immutable 表示资源“在其新鲜度生命周期内不会更新”。因此,浏览器在从浏览器缓存提供资源时不会重新验证资源,从而消除了不必要的服务器请求。很遗憾,只有 Firefox 和 Safari 支持此指令,基于 Chromium 的浏览器不支持该指令。此问题跟踪了 Chromium 对 Cache-Control: immutable 的支持。给此问题加注星标有助于鼓励用户支持此功能。

如需详细了解 HTTP 缓存,请参阅使用 HTTP 缓存防止不必要的网络请求

微调

下面简要说明了 CDN 缓存如何工作:资源的网址用作缓存和从缓存中检索资源的键。实际上,这仍然是绝大多数情况,但是由于请求标头和查询参数等因素的影响,情况有些复杂。因此,重写请求网址是一项重要的技术,不仅可最大限度地提高 CHR,还可确保向用户提供正确的内容。正确配置的 CDN 实例能够在过于精细的缓存(有损 CHR)和不够精细的缓存(导致向用户提供错误响应)之间取得适当的平衡。

查询参数

默认情况下,CDN 在缓存资源时会考虑查询参数。但是,对查询参数处理的细微调整可能会对 CHR 产生显著影响。例如:

  • 不必要的查询参数

    默认情况下,CDN 会分别缓存 example.com/blogexample.com/blog?referral_id=2zjk,即使它们可能是相同的底层资源也是如此。修复了此问题,只需将 CDN 的配置调整为忽略 referral\_id 查询参数即可。

  • 查询参数 order

    CDN 会将 example.com/blog?id=123&query=dogsexample.com/blog?query=dogs&id=123 分开缓存。对于大多数网站,查询参数顺序无关紧要,因此将 CDN 配置为对查询参数进行排序(从而将用于缓存服务器响应的网址标准化)会增加 CHR。

更改

Vary 响应标头会告知缓存,与特定网址对应的服务器响应可能会因请求中设置的标头(例如 Accept-LanguageAccept-Encoding 请求标头)而异。因此,它会指示 CDN 单独缓存这些响应。CDN 未广泛支持 Vary 标头,这可能导致没有从缓存中提供其他可缓存的资源。

尽管 Vary 标头是一个有用的工具,但不当使用会破坏 CHR。此外,如果您使用 Vary,对请求标头进行标准化将有助于改善 CHR。例如,如果不标准化,请求标头 Accept-Language: en-USAccept-Language: en-US,en;q=0.9 将生成两个单独的缓存条目,即使两者的内容可能相同。

Cookie

Cookie 通过 Cookie 标头在请求上设置;它们通过 Set-Cookie 标头在响应中设置。考虑到缓存通常不会缓存包含此标头的服务器响应,应避免不必要地使用 Set-Cookie 标头。

性能特点

本节讨论 CDN 通常作为其核心产品的一部分提供的性能功能。很多网站忘记启用这些功能,因此错失良机。

压缩

所有基于文本的响应都应使用 gzip 或 Brotli 压缩。如果可以选择,请选择 Brotli 而非 gzip。Brotli 是一种较新的压缩算法,并且与 gzip 相比,它可以实现更高的压缩比率。

Brotli 压缩功能提供两种类型的 CDN 支持:“Brotli from origin”和“自动 Brotli 压缩”。

原汁原味的 Brotli

来自源的 Brotli 是指 CDN 提供的资源由源站压缩的 Brotli。尽管看起来所有 CDN 都应该能够支持这种开箱即用的功能,但这要求 CDN 能够缓存多个版本(即 gzip 压缩版本和 Brotli 压缩版本)的资源,对应于给定的网址。

自动 Brotli 压缩

自动 Brotli 压缩是指资源由 CDN 压缩的 Brotli。CDN 可以压缩可缓存和不可缓存的资源。

首次请求某个资源时,系统会使用“足够好”的压缩机制来提供该资源,例如 Brotli-5。这种类型的压缩对可缓存资源和不可缓存资源均适用。

同时,如果资源可缓存,CDN 将通过离线处理,以更强大但速度慢得多的压缩级别(例如 Brotli-11)压缩该资源。压缩完成后,压缩程度较高的版本将被缓存,并用于后续请求。

压缩最佳实践

想要最大限度提高性能的网站应该在其源服务器和 CDN 上应用 Brotli 压缩。在源站进行 Brotli 压缩,可最大限度地减少无法从缓存传送的资源的传输大小。为防止服务请求出现延迟,源站应使用相当保守的压缩级别来压缩动态资源(例如 Brotli-4);可以使用 Brotli-11 压缩静态资源。如果源不支持 Brotli,可以使用 gzip-6 压缩动态资源,也可以使用 gzip-9 压缩静态资源。

TLS 1.3

TLS 1.3 是最新版传输层安全协议 (TLS),即 HTTPS 使用的加密协议。与 TLS 1.2 相比,TLS 1.3 可提供更好的隐私保护和性能。

TLS 1.3 将 TLS 握手从两次往返缩短为一次。对于使用 HTTP/1 或 HTTP/2 的连接,将 TLS 握手时间缩短为一次往返,可有效将连接设置时间缩短 33%。

TLS 1.2 和 TLS 1.3 握手比较

HTTP/2 和 HTTP/3

与 HTTP/1 相比,HTTP/2 和 HTTP/3 都提供性能优势。在两者中,HTTP/3 具有更大的潜在性能优势。HTTP/3 尚未完全标准化,但一旦发生这种情况,就会受到广泛支持

HTTP/2

如果您的 CDN 尚未默认启用 HTTP/2,则应考虑启用该功能。与 HTTP/1 相比,HTTP/2 具有诸多性能优势,并且受所有主流浏览器支持。HTTP/2 的性能功能包括:多路复用流优先级标头压缩

  • 多路复用

    多路复用可以说是 HTTP/2 最重要的功能。多路复用可让单个 TCP 连接同时处理多个请求-响应对。这样可省去不必要的连接设置开销;考虑到浏览器在给定时间可打开的连接数是有限的,这也意味着浏览器现在能够并行请求更多网页的资源。从理论上讲,多路复用不需要进行 HTTP/1 优化(如串联和精灵表),但在实践中,由于较大文件的压缩效果更佳,因此这些技术仍然适用。

  • 数据流优先级

    多路复用支持多个并行流;视频流优先级提供了一个用于传达其中每个视频流的相对优先级的接口。这有助于服务器先发送最重要的资源,即使资源并未先被请求也是如此。

视频流优先级由浏览器通过依存关系树表示,只是首选项语句:换言之,服务器没有义务满足(甚至考虑)浏览器提供的优先级。当更多网站通过 CDN 提供时,数据流优先级更有效。

HTTP/2 资源优先级的 CDN 实现差异巨大。如需确定您的 CDN 是否完全且正确支持 HTTP/2 资源优先级设置,请查看 Is HTTP/2 Fast Yet?

虽然将 CDN 实例切换到 HTTP/2 主要是一个切换开关,但在在生产环境中启用此更改之前,请务必对此更改进行全面测试。HTTP/1 和 HTTP/2 使用相同的请求标头和响应标头约定,但如果不遵守这些约定,HTTP/2 的宽容度会大大降低。因此,启用 HTTP/2 后,诸如在标头中添加非 ASCII 或大写字符之类的非规范做法可能会开始导致错误。如果发生这种情况,浏览器尝试下载该资源的操作将会失败。下载失败的尝试将显示在开发者工具的“网络”标签页中。此外,控制台中会显示错误消息“ERR_HTTP2_PROTOCOL_ERROR”。

HTTP/3

HTTP/3HTTP/2 的继任者。截至 2020 年 9 月,所有主流浏览器均提供对 HTTP/3 的实验性支持,部分 CDN 支持 HTTP/3。性能是 HTTP/3 优于 HTTP/2 的主要优势。具体来说,HTTP/3 消除了连接级别的队头屏蔽问题,缩短了连接设置时间。

  • 消除队头屏蔽

    HTTP/2 引入了多路复用功能,该功能允许使用单个连接同时传输多个数据流。然而,使用 HTTP/2 时,一个丢弃的数据包会阻止连接上的所有数据流(这种现象称为队头阻塞)。使用 HTTP/3 时,丢弃的数据包仅阻塞单个数据流。这一改进主要是 HTTP/3 使用 UDP(HTTP/3 通过 QUIC 使用 UDP)而非 TCP 的结果。这使得 HTTP/3 对通过拥塞或有损网络进行的数据传输尤其有用。

显示 HTTP/1、HTTP/2 和 HTTP/3 之间的数据传输差异的图表
  • 缩短连接设置时间

    HTTP/3 使用 TLS 1.3,因此具有同样的性能优势:建立新连接只需一次往返,而恢复现有连接则不需要任何往返。

TLS 1.2、TLS 1.3、TLS 1.3 0-RTT 和 HTTP/3 之间的连接恢复比较

在网络连接状况不佳时,HTTP/3 对用户的影响最大:这不仅是因为 HTTP/3 比其前身能够更好地处理丢包,还因为在延迟时间较长的网络上,0-RTT 或 1-RTT 连接设置可以节省的绝对时间。

图片优化

CDN 图片优化服务通常侧重于图片优化,这些优化可自动应用以缩减图片传输大小。例如:去除 EXIF 数据、应用无损压缩,以及将图片转换为较新的文件格式(例如 WebP)。在网页中,图片约占传输字节的 50%,因此优化图片可以显著缩减网页大小。

缩减大小

缩减大小功能会从 JavaScript、CSS 和 HTML 中移除不必要的字符。最好在源服务器而非 CDN 上进行缩减。网站所有者对需要缩减的代码拥有更多背景信息,因此通常会比 CDN 采用更激进的缩减技术。但是,如果您无法选择在源站缩减代码,那么通过 CDN 进行缩减是一个不错的选择。

总结

  • 使用 CDN:CDN 可快速分发资源、减少源服务器的负载,并有助于应对流量高峰。
  • 尽可能主动缓存内容:可以并且应该缓存静态内容和动态内容,尽管缓存时长有所不同。请定期审核您的网站,确保内容缓存效果最佳。
  • 启用 CDN 性能功能:Brotli、TLS 1.3、HTTP/2 和 HTTP/3 等功能可以进一步提高性能。