内容分发网络 (CDN)

通过使用内容分发网络提高性能。

Katie Hempenius
Katie Hempenius

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

概述

内容分发网络由服务器网络组成,这些服务器经过优化,可快速向用户交付内容。尽管 CDN 最为人所知的是用于提供缓存内容,但 CDN 还可以改进不可缓存内容的交付。一般来说,您的网站通过 CDN 交付的内容越多越好。

从宏观层面来看,CDN 的性能优势源于以下几个原则:CDN 服务器比源服务器更靠近用户,因此具有更短的往返时间 (RTT)延迟;网络优化使 CDN 能够比从源服务器“直接”加载内容更快地交付内容;最后,CDN 缓存消除了请求访问源服务器的需求。

资源交付

尽管这可能看起来违反直觉,但使用 CDN 交付资源(即使是不可缓存的资源)通常也比让用户从您的服务器“直接”加载资源更快。

当使用 CDN 从源服务器交付资源时,将在客户端和附近的 CDN 服务器之间建立新连接。旅程的剩余部分(换句话说,CDN 服务器和源服务器之间的数据传输)发生在 CDN 的网络上 - 这通常包括与源服务器的现有持久连接。这有双重好处:尽可能靠近用户终止新连接消除了不必要的连接建立成本(建立新连接成本高昂且需要多次往返);使用预热连接允许数据以最大可能的吞吐量立即传输。

Comparison of connection setup with and without a CDN

一些 CDN 通过将流量路由到源服务器,甚至通过分布在整个互联网上的多个 CDN 服务器,从而进一步改进了这一点。CDN 服务器之间的连接通过可靠且高度优化的路由进行,而不是由 边界网关协议 (BGP) 确定的路由。尽管 BGP 是互联网事实上的路由协议,但其路由决策并不总是以性能为导向。因此,BGP 确定的路由可能不如 CDN 服务器之间微调的路由性能好。

Comparison of connection setup with and without a CDN

缓存

在 CDN 服务器上缓存资源消除了请求必须一直访问源服务器才能被提供服务的需求。因此,资源交付速度更快;这也减少了源服务器的负载。

向缓存添加资源

填充 CDN 缓存最常用的方法是让 CDN 在需要时“拉取”资源 - 这被称为“源拉取”。首次从缓存请求特定资源时,CDN 将从源服务器请求该资源并缓存响应。通过这种方式,缓存的内容会随着请求更多未缓存的资源而随着时间的推移逐渐构建起来。

从缓存中删除资源

CDN 使用缓存逐出定期从缓存中删除不太有用的资源。此外,网站所有者可以使用清除来显式删除资源。

  • 缓存逐出

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

  • 清除

    清除(也称为“缓存失效”)是一种从 CDN 缓存中删除资源的机制,而无需等待其过期或被逐出。它通常通过 API 执行。在需要撤回内容的情况下(例如,更正错别字、定价错误或不正确的新闻文章),清除至关重要。最重要的是,它还可以在网站的缓存策略中发挥关键作用。

    如果 CDN 支持近乎即时的清除,则清除可以用作管理动态内容缓存的机制:使用较长的 TTL 缓存动态内容,然后在每次更新资源时清除该资源。通过这种方式,即使事先不知道资源何时会更改,也可以最大限度地延长动态资源的缓存持续时间。此技术有时被称为“hold-till-told 缓存”。

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

可缓存资源

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

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

    私有资源包含旨在供单个用户使用的数据,因此不应由 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 获得的准确性能。

对最大内容渲染 (LCP) 的影响

正如本文前面概述的那样,CDN 的主要目的是通过将资源分发到地理位置上更靠近用户的服务器来减少延迟。因此,CDN 的主要好处是它可以提高加载性能。特别是,当将 CDN 引入网站的服务器端架构时,资源的首字节时间 (TTFB)可以得到显着改善。

虽然 TTFB 不是以用户为中心的性能指标,但它诊断最大内容渲染 (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 服务的资源的 URL,以指向您创建的 static.example.com 子域。

虽然此时您的 CDN 将设置完成,但您的配置可能仍存在效率低下之处。本文的下两节将解释如何通过提高缓存命中率和启用性能功能来充分利用您的 CDN。

提高缓存命中率

有效的 CDN 设置将尽可能多地从缓存中提供资源。这通常通过缓存命中率 (CHR) 来衡量。缓存命中率定义为在给定时间间隔内缓存命中次数除以总请求数。

新初始化的缓存的 CHR 为 0,但随着缓存填充资源,CHR 会增加。对于大多数网站来说,90% 的 CHR 是一个不错的目标。您的 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 缓存工作原理的一个稍微简化的解释是,资源的 URL 用作从缓存中缓存和检索资源的键。实际上,这仍然绝大多数是正确的,但由于请求标头和查询参数等事物的影响而略有复杂。因此,重写请求 URL 是最大化 CHR 并确保向用户提供正确内容的重要技术。正确配置的 CDN 实例在过度精细的缓存(会损害 CHR)和不够精细的缓存(会导致向用户提供不正确的响应)之间取得正确的平衡。

查询参数

默认情况下,CDN 在缓存资源时会考虑查询参数。但是,对查询参数处理进行小的调整可能会对 CHR 产生重大影响。例如

  • 不必要的查询参数

    默认情况下,CDN 会分别缓存 example.com/blogexample.com/blog?referral_id=2zjk,即使它们可能是相同的底层资源。这可以通过调整 CDN 的配置以忽略 referral\_id 查询参数来解决。

  • 查询参数顺序

    CDN 将分别缓存 example.com/blog?id=123&query=dogsexample.com/blog?query=dogs&id=123。对于大多数网站来说,查询参数顺序无关紧要,因此将 CDN 配置为对查询参数进行排序(从而规范化用于缓存服务器响应的 URL)将提高 CHR。

Vary

Vary 响应标头通知缓存,与特定 URL 对应的服务器响应可能因请求中设置的标头而异(例如,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 相比,它可以实现更高的压缩率。

CDN 对 Brotli 压缩有两种类型的支持:“源 Brotli 压缩”和“自动 Brotli 压缩”。

源 Brotli 压缩

源 Brotli 压缩是指 CDN 提供由源服务器进行 Brotli 压缩的资源。尽管这看起来像是所有 CDN 都应该能够开箱即用支持的功能,但它要求 CDN 能够缓存与给定 URL 对应的资源的多个版本(换句话说,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%。

Comparison of the TLS 1.2 and TLS 1.3 handshakes

HTTP/2 和 HTTP/3

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

HTTP/2

如果您的 CDN 尚未默认启用 HTTP/2,您应考虑将其打开。HTTP/2 比 HTTP/1 提供了多项 性能优势,并且得到所有主要浏览器的 支持。HTTP/2 的性能功能包括:多路复用流优先级标头压缩

  • 多路复用

    多路复用可以说是 HTTP/2 最重要的功能。多路复用使单个 TCP 连接能够同时服务多个请求-响应对。这消除了不必要的连接建立的开销;鉴于浏览器在给定时间内可以打开的连接数是有限的,这也意味着浏览器现在能够并行请求更多页面的资源。从理论上讲,多路复用消除了对 HTTP/1 优化的需求,例如串联和雪碧图 - 但是,在实践中,这些技术仍然相关,因为较大的文件压缩效果更好。

  • 流优先级

    多路复用启用多个并发流;流优先级提供了一个接口,用于传达这些流中每个流的相对优先级。这有助于服务器首先发送最重要的资源 - 即使它们不是首先被请求的。

流优先级由浏览器通过依赖树表示,并且仅仅是偏好的声明:换句话说,服务器没有义务满足(甚至考虑)浏览器提供的优先级。当更多网站通过 CDN 提供服务时,流优先级变得更加有效。

CDN 对 HTTP/2 资源优先级的实现差异很大。要确定您的 CDN 是否完全且正确地支持 HTTP/2 资源优先级,请查看 Is HTTP/2 Fast Yet?

尽管将您的 CDN 实例切换到 HTTP/2 主要只是拨动开关的问题,但在生产环境中启用此更改之前,彻底测试此更改非常重要。HTTP/1 和 HTTP/2 对请求和响应标头使用相同的约定 - 但当这些约定未得到遵守时,HTTP/2 的容忍度要低得多。因此,一旦启用 HTTP/2,在标头中包含非 ASCII 或大写字符等不符合规范的做法可能会开始导致错误。如果发生这种情况,浏览器下载资源的尝试将失败。失败的下载尝试将在 DevTools 的“网络”选项卡中可见。此外,控制台中将显示错误消息“ERR_HTTP2_PROTOCOL_ERROR”。

HTTP/3

HTTP/3HTTP/2 的继任者。截至 2020 年 9 月,所有主要浏览器都对 HTTP/3 进行了实验性 支持,并且一些 CDN 支持它。性能是 HTTP/3 相对于 HTTP/2 的主要优势。具体来说,HTTP/3 消除了连接级别的队头阻塞,并减少了连接建立时间。

  • 消除队头阻塞

    HTTP/2 引入了多路复用,该功能允许使用单个连接同时传输多个数据流。但是,对于 HTTP/2,单个丢包会阻塞连接上的所有流(一种称为队头阻塞的现象)。使用 HTTP/3,丢包仅阻塞单个流。这种改进在很大程度上是 HTTP/3 使用 UDP(HTTP/3 通过 QUIC 使用 UDP)而不是 TCP 的结果。这使得 HTTP/3 特别适用于在拥塞或有损网络上的数据传输。

Diagram showing the differences in data transmission between HTTP/1, HTTP/2, and HTTP/3
  • 减少连接建立时间

    HTTP/3 使用 TLS 1.3,因此共享其性能优势:建立新连接仅需要一次往返,而恢复现有连接不需要任何往返。

Comparison of connection resumption between TLS 1.2, TLS 1.3, TLS 1.3 0-RTT, and 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 等功能进一步提高了性能。