优化加载第一个字节所需时间

了解如何针对“首字节时间”指标进行优化。

首字节时间 (TTFB) 是一项基础的网页性能指标,会排在所有其他有意义的用户体验指标(例如 First Contentful Paint (FCP)Largest Contentful Paint (LCP))之前。这意味着,较高的 TTFB 值会延长其后续指标的时间。

建议您的服务器对导航请求做出足够快速的响应,以便在“良好”阈值内为 75% 的用户体验 FCP。一般而言,大多数网站都应力求将 TTFB 控制在 0.8 秒或更短的水平。

良好 TTFB 值不超过 0.8 秒,不佳值大于 1.8 秒,且介于两者之间的所有值都需要改进

如何衡量 TTFB

在优化 TTFB 之前,您需要观察它对您网站的用户有何影响。您应依靠实测数据作为观察 TTFB 的主要来源,因为它会受到重定向的影响,而基于实验室的工具通常使用最终到达网址来衡量,因此缺少这种额外的延迟。

通过 PageSpeed Insights,可同时获取 Chrome 用户体验报告中公开网站的现场信息和实验室信息。

真实用户的 TTFB 显示在顶部的了解真实用户的体验部分:

PageSpeed Insights 真实用户数据,包括 TTFB 指标的实测数据。

服务器响应时间审核中会显示 TTFB 的子集:

服务器响应时间审核

如需了解如何在现场和实验室中衡量 TTFB 的更多方法,请参阅 TTFB 指标页面

使用 Server-Timing 在现场调试高 TTFB

Server-Timing 响应标头可用于应用后端,以衡量可能导致高延迟的不同后端进程。标头值的结构非常灵活,至少接受您定义的句柄。可选值包括时长值(通过 dur)以及简单易懂的说明(通过 desc)。

Serving-Timing 可用于衡量许多应用后端进程,但也有一些需要特别注意的事项:

  • 数据库查询
  • 服务器端呈现时间(如果适用)
  • 磁盘搜寻次数
  • 边缘服务器缓存命中/未命中(如果使用 CDN)

Server-Timing 条目的所有部分都用英文冒号分隔,多个条目可以以英文逗号分隔:

// Two metrics with descriptions and values
Server-Timing: db;desc="Database";dur=121.3, ssr;desc="Server-side Rendering";dur=212.2

您可以使用应用后端选择的语言来设置标头。例如,在 PHP 中,您可以对标头进行如下设置:

<?php
// Get a high-resolution timestamp before
// the database query is performed:
$dbReadStartTime = hrtime(true);

// Perform a database query and get results...
// ...

// Get a high-resolution timestamp after
// the database query is performed:
$dbReadEndTime = hrtime(true);

// Get the total time, converting nanoseconds to
// milliseconds (or whatever granularity you need):
$dbReadTotalTime = ($dbReadEndTime - $dbReadStarTime) / 1e+6;

// Set the Server-Timing header:
header('Server-Timing: db;desc="Database";dur=' . $dbReadTotalTime);
?>

设置此标题后,系统会显示您可以在实验字段中使用的信息。

在此字段中,任何设置了 Server-Timing 响应标头的页面都将填充 Navigation Timing API 中的 serverTiming 属性:

// Get the serverTiming entry for the first navigation request:
performance.getEntries('navigation')[0].serverTiming.forEach(entry => {
  // Log the server timing data:
  console.log(entry.name, entry.description, entry.duration);
});

在该实验中,Server-Timing 响应标头中的数据将在 Chrome 开发者工具中 Network 标签页的“计时”面板中直观显示:

Chrome DevTools 的“Network”标签页中的 Server-Timing 标头值的可视化效果。在此图片中,Server-Timing 标头值测量了 CDN 边缘服务器是否遇到缓存命中或未命中,以及从边缘和源服务器检索资源所需的时间。

Chrome 开发者工具的“网络”标签页中直观呈现的 Server-Timing 响应标头。在这里,Server-Timing 用于衡量对资源的请求是否已到达 CDN 缓存,以及请求到达 CDN 的边缘服务器,然后到达源站所需的时间。

通过分析可用数据确定 TTFB 存在问题后,您就可以开始解决问题。

优化 TTFB 的方法

优化 TTFB 的最大挑战在于,虽然 Web 的前端堆栈始终是 HTML、CSS 和 JavaScript,但后端堆栈可能有很大差异。许多后端堆栈和数据库产品都有自己的优化技术。因此,本指南将重点介绍适用于大多数架构的内容,而不是仅关注针对特定堆栈的指南。

针对具体平台的指南

您为网站使用的平台可能会严重影响 TTFB。例如,WordPress 性能受插件数量和质量或所使用的主题的影响。如果平台进行了自定义,其他平台也会受到类似影响。对于本博文中更常规的性能建议,您应参阅相应平台的相关文档,以获取针对供应商的建议。有关缩短服务器响应时间的 Lighthouse 审查还包含一些有限的堆栈专用指南

托管,托管,托管

在考虑其他优化方法之前,首先应该考虑托管。虽然此处并未提供太多的具体指导,但一般而言,您需要确保您网站的主机能够处理您向其发送的流量。

共享托管通常速度会变慢。如果您运营的是一个主要提供静态文件的小型个人网站,这很可能没有问题,下面的一些优化技巧将帮助您尽可能降低 TTFB。

但是,如果您运行的大型应用涉及众多用户,并且涉及个性化、数据库查询和其他密集型服务器端操作,那么您的托管选择对于降低现场 TTFB 至关重要。

选择托管服务提供商时,需要注意以下几点:

  • 为您的应用实例分配多少内存?如果您的应用内存不足,则会抖动并难以尽快提供页面。
  • 您的托管服务提供商是否确保您的后端堆栈处于最新状态?随着新版本的应用后端语言、HTTP 实现和数据库软件的发布,该软件的性能将随着时间的推移而不断改进。与托管此类重要维护工作的托管服务提供商合作至关重要。
  • 如果您有非常具体的应用要求,并希望以最低级别访问服务器配置文件,请询问是否有必要自定义自己的应用实例的后端。

许多托管服务提供商会为您处理这些工作,但如果您开始观察到较长的 TTFB 值(即使是在专门的托管服务提供商中),这可能表明您可能需要重新评估您当前的托管服务提供商的功能,以便尽可能提供最佳的用户体验。

使用内容分发网络 (CDN)

虽然“CDN 用法”这个主题很老了,但其背后有充分的理由:您拥有一个经过精心优化的应用后端,但远离源服务器的用户在实际运行过程中仍可能会遇到较高的 TTFB。

CDN 通过使用分布式服务器网络,将资源缓存在距离用户较近的服务器上,从而解决了用户与源服务器之间的邻近性问题。这些服务器称为“边缘服务器”。

CDN 提供商可能还会提供边缘服务器以外的优势:

  • CDN 提供商通常提供极快的 DNS 解析时间。
  • CDN 可能会使用新型协议(例如 HTTP/2 或 HTTP/3)从边缘服务器传送您的内容。
  • 特别要指出的是,HTTP/3 利用 UDP 协议解决了 TCP(HTTP/2 所依赖)中存在的队头阻塞问题。
  • CDN 也可能会提供现代版本的 TLS,以降低 TLS 协商时间中涉及的延迟时间。TLS 1.3 尤其旨在使 TLS 协商尽可能缩短。
  • 某些 CDN 提供商提供了一项通常称为“边缘工作器”的功能,该功能使用与 Service Worker API 类似的 API 来拦截请求、以编程方式管理边缘缓存中的响应,或者完全重写响应。
  • CDN 提供商非常擅长进行压缩优化。自行压缩并非易事,并且在某些情况下可能会导致响应速度变慢,因为标记必须动态生成。
  • CDN 提供商还将自动缓存静态资源的压缩响应,以实现压缩比和响应时间的最佳组合。

虽然采用 CDN 所需的工作量各不相同,但如果您的网站尚未使用 CDN,则您应优先考虑优化 TTFB。

尽可能使用缓存的内容

借助 CDN,您可以将内容缓存在实际距离访问者较近的边缘服务器上,但前提是内容配置了适当的 Cache-Control HTTP 标头。虽然这不适用于个性化内容,但如果要求必须行程全部返回源站,则可能会降低 CDN 的大部分价值。

对于频繁更新内容的网站,即便是较短的缓存时间,也能为繁忙网站带来显著的性能提升,因为在这段时间内,只有第一个访问者经历返回到源服务器的完全延迟,而其他所有访问者可以重复使用边缘服务器的缓存资源。有些 CDN 允许在网站版本上执行缓存失效操作,这样能达到两全其美的效果 - 缓存时间较长,但可在需要时即时更新。

即使缓存已正确配置,通过使用唯一的查询字符串参数进行分析衡量,也可以忽略这一点。尽管这些内容在 CDN 上是相同的,但这些内容可能在 CDN 上看起来有所不同,因此系统不会使用缓存的版本。

访问时间较早或访问频率较低的内容也可能不会被缓存,从而导致某些网页上的 TTFB 值高于其他网页上的 TTFB 值。增加缓存时间可以减少这一影响,但请注意,缓存时间越长,传送可能过时的内容的可能性就越大。

缓存内容的影响不只影响使用 CDN 的内容。当缓存的内容无法重复使用时,服务器基础架构可能需要通过昂贵的数据库查询来生成内容。访问频率较高的数据或预缓存的页面通常可以有更好的效果。

避免多次网页重定向

TTFB 较高的一个常见原因是重定向。当文档的导航请求收到通知浏览器相应资源位于其他位置的响应时,就会发生重定向。一个重定向无疑会给导航请求增加不必要的延迟,但如果该重定向指向的其他资源导致了另一个重定向(以此类推),这种情况无疑会更严重。这尤其会对通过广告或简报吸引大量访问者的网站造成影响,因为这些网站经常出于衡量目的经由分析服务进行重定向。消除由您直接控制的重定向有助于实现较好的 TTFB。

重定向有两种类型:

  • 同源重定向,这种重定向完全发生在您的网站上。
  • 跨域重定向:这种重定向最初在另一个来源(例如,社交媒体网址缩短服务)上发生,然后才到达您的网站。

您需要专注于消除同源重定向,因为这将由您直接控制。这涉及到检查您网站上的链接,看看是否有任何链接会产生 302301 响应代码。这通常是由于未包含 https:// 架构(因此浏览器默认使用 http://,然后进行重定向)或网址未适当地包含或排除尾部斜杠的结果。

跨源重定向较为复杂,因为这些重定向通常超出您的控制范围,但请尽可能避免多次重定向,例如在共享链接时使用多个链接缩短工具。请确保提供给广告客户或简报的网址是正确的最终到达网址,以免再向这些服务使用的网址添加重定向。

另一个重要的重定向时间来源可能来自 HTTP 到 HTTPS 重定向。解决此问题的一种方法是使用 Strict-Transport-Security 标头 (HSTS),该标头会在首次访问某个源时强制执行 HTTPS,然后告知浏览器在以后访问时立即通过 HTTPS 架构访问该源。

制定良好的 HSTS 政策后,您就可以将网站添加到 HSTS 预加载列表,从而在用户首次访问某个来源时加快速度。

将标记流式传输到浏览器

浏览器已经过优化,可在流式传输标记时高效处理标记,这意味着,当标记从服务器传入时,系统会分块对其进行处理。在涉及大型标记有效负载的情况下,这一点至关重要,因为这意味着浏览器可以逐步解析标记块,而不是等待整个响应到达后再开始解析。

虽然浏览器擅长处理流式传输标记,但您必须尽一切努力使数据流能够正常进行,以便这些最初的标记元素尽快发挥作用。如果后端阻止了访问,那就是问题所在。由于后端堆栈数量众多,因此本指南不会介绍每一个堆栈以及每个特定堆栈可能出现的问题。

例如,React 以及其他可在服务器上按需呈现标记的框架就采用了同步方法进行服务器端呈现。不过,较新版本的 React 在呈现标记时实现了用于流式传输标记的服务器方法。这意味着,在发送整个响应之前,您不必等待 React 服务器 API 方法呈现整个响应。

确保标记快速流式传输到浏览器的另一种方法是依靠静态呈现,该功能会在构建时生成 HTML 文件。由于完整文件可立即使用,网络服务器可立即开始发送文件,而 HTTP 的固有特性将生成流式标记。虽然这种方法并不适合每个网站上的每个网页(例如需要在用户体验过程中进行动态响应的网页),但它可以让那些不需要标记即可针对具体用户进行个性化设置的网页大有裨益。

使用 Service Worker

Service Worker API 可能会对文档及其所加载资源的 TTFB 产生巨大影响。其原因在于 Service Worker 充当浏览器和服务器之间的代理,但这是否会影响您网站的 TTFB 取决于您设置 Service Worker 的方式,以及该设置是否符合您的应用要求。

  • 对资产使用过时重新验证策略如果某项资源位于 Service Worker 缓存中(无论是文档还是文档所需的资源),“过时时重新验证”策略将首先从缓存中提供该资源,然后在后台下载该资源并从缓存中提供它以供将来交互。
    • 如果您的文档资源不会经常变化,那么使用“同时重新验证”策略会使网页的 TTFB 几乎是即时完成的。不过,如果您的网站发送动态生成的标记(例如根据用户是否通过身份验证而变化的标记),这种方法就不太好用。在这种情况下,您始终需要先连接到网络,以便使文档尽可能保持最新状态。
    • 如果您的文档加载了以特定频率变化的非关键资源,但提取过时资源(例如选择图片或其他不关键资源)不会对用户体验产生很大影响,那么,您可以使用“在重新验证时过时”策略大大减少这些资源的 TTFB。
  • 对客户端呈现的应用使用 App Shell 模型。此模型最适合 SPA,在这种模式下,页面“外壳”可以从 Service Worker 缓存即时传送,而页面的动态内容会在页面生命周期的后期填充和呈现。

103 Early Hints 用于渲染关键型资源

无论应用后端的优化程度如何,服务器仍需要完成大量工作来准备响应,其中包括昂贵(但必要的)数据库工作,这些工作会使导航响应无法尽快到达。这可能会造成一些后续渲染关键型资源出现延迟,例如 CSS 或(在某些情况下)在客户端呈现标记的 JavaScript。

103 Early Hints 标头是一个早期响应代码,服务器可在后端忙于准备标记时将其发送到浏览器。此标头可用于提示浏览器,在准备标记时,网页应开始下载对呈现至关重要的资源。对于支持的浏览器,可加快文档渲染 (CSS) 和核心网页功能 (JavaScript) 的可用性。

总结

由于后端应用堆栈的组合非常多,因此在降低网站 TTFB 方面所能做的所有方法都不在一篇文章中。不过,您可以探索这些选项,尝试让服务器端的运行速度略快一点。

与优化每项指标一样,方法大体上相似:测量实际应用的 TTFB,使用实验室工具深入了解原因,然后尽可能采取优化措施。这里的每一种方法可能对您的情况都行之有效,但有些是可行的。与往常一样,您需要密切关注您的现场数据,并根据需要进行调整,以确保提供最快的用户体验。

主打图片由 Taylor Vick 拍摄,来源为 Uncapture。