优化首字节时间

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

首字节时间 (TTFB) 是一个基础 Web 性能指标,先于所有其他有意义的用户体验指标,例如 首次内容绘制 (FCP)最大内容绘制 (LCP)。这意味着较高的 TTFB 值会增加后续指标的时间。

建议您的服务器对导航请求做出足够快的响应,以便 75% 分位数 的用户在 “良好”阈值内 体验到 FCP。作为粗略的指南,大多数网站应力求 TTFB 为 0.8 秒或更短

Good TTFB values are 0.8 seconds or less, poor values are greater than 1.8 seconds, and anything in between needs improvement
良好的 TTFB 值为 0.8 秒或更短,较差的值大于 1.8 秒

如何衡量 TTFB

在优化 TTFB 之前,您需要观察它如何影响您网站的用户。您应该依靠 现场数据 作为观察 TTFB 的主要来源,因为它会受到重定向的影响,而基于实验室的工具通常使用最终 URL 进行测量,因此会遗漏这种额外的延迟。

PageSpeed Insights 是获取 Chrome 用户体验报告中提供的公共网站的现场和实验室信息的一种方法。

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

PageSpeed Insights real user data, including field data for the TTFB metric.
PageSpeed Insights 现场数据。

对于实验室数据,TTFB 的一个子集显示在 服务器响应时间审核

Server response time audit
PageSpeed Insights 服务器响应时间审核。

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

了解现场和实验室 TTFB 之间的差异

实验室和现场 TTFB 可能因多种原因而异,当它们确实不同时,重要的是要了解原因,以便能够有效地使用实验室数据来改善您的用户体验。

  • 当实验室 TTFB 远大于现场 TTFB 时,这表明实验室环境比典型的用户体验更受限制。这不一定是一个问题,因为实验室结果和建议可能仍然有效,但可能只是夸大了影响和改进。

  • 当现场 TTFB 远大于实验室 TTFB 时,这表明在实验室运行期间未显现的问题,例如使用服务器端缓存、重定向或网络差异。在这种情况下,实验室结果和建议可能不太有用,因为它们会遗漏主要问题之一。

    要查看服务器端缓存是否影响实验室 TTFB,请尝试测试不太常见的页面或使用不同的 URL 参数来获取未缓存的内容,以查看 TTFB 是否更符合现场 TTFB。如果您能够使用特定的 URL 参数绕过服务器端缓存,这也可能很有用。请参阅 缓存内容部分

    对于重定向和网络差异,分析流量如何进入我们的网站以及来自何处,可以帮助诊断这些是否是潜在问题。

使用 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 - $dbReadStartTime) / 1e+6;

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

设置此标头后,它将显示您可以在 实验室现场 使用的信息。

在现场,任何设置了 Server-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 DevTools 的 网络 选项卡的“计时”面板中可视化

A visualization of Server-Timing header values in the Network tab of Chrome DevTools. In this image, the Server-Timing header values are measuring whether or not a CDN edge server encountered a cache hit or miss, as well as the time to retrieve the resource from the edge and the origin server.
Chrome DevTools 的“网络”选项卡中的 Server-Timing 标头值。

在 Chrome DevTools 的“网络”选项卡中可视化的 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 依赖于 TCP)中存在的队头阻塞问题。
  • CDN 很可能还会提供现代版本的 TLS,从而降低 TLS 协商时间中涉及的延迟。特别是 TLS 1.3 旨在尽可能缩短 TLS 协商时间。
  • 一些 CDN 提供商提供一项通常称为“边缘工作程序”的功能,该功能使用类似于 Service Worker API 的 API 来拦截请求、以编程方式管理边缘缓存中的响应或完全重写响应。
  • CDN 提供商非常擅长优化压缩。压缩本身很难做好,并且在某些情况下可能会导致动态生成的标记响应时间变慢,这些标记必须即时压缩。
  • CDN 提供商还将自动缓存静态资源的压缩响应,从而实现压缩率和响应时间的最佳组合。

虽然采用 CDN 涉及的努力程度从微不足道到意义重大不等,但如果您的网站尚未使用 CDN,则应优先考虑在优化 TTFB 时采用 CDN。

尽可能使用缓存内容

CDN 允许内容缓存在物理位置更靠近访问者的边缘服务器上,前提是内容配置了适当的 Cache-Control HTTP 标头。虽然这不适用于个性化内容,但需要一路返回源站可能会抵消 CDN 的大部分价值。

对于频繁更新内容的网站,即使是较短的缓存时间也可能为繁忙的网站带来显着的性能提升,因为在该时间内只有第一个访问者会体验到返回源服务器的完整延迟,而所有其他访问者都可以重用来自边缘服务器的缓存资源。一些 CDN 允许在站点发布时进行缓存失效,从而实现两全其美——较长的缓存时间,但在需要时可以即时更新。

即使缓存配置正确,也可以通过使用唯一的查询字符串参数进行分析测量来忽略它。尽管内容相同,但这些内容对于 CDN 来说可能看起来是不同的,因此不会使用缓存版本。

较旧或访问量较少的内容也可能未被缓存,这可能会导致某些页面上的 TTFB 值高于其他页面。增加缓存时间可以减少这种情况的影响,但请注意,随着缓存时间的增加,提供可能过时的内容的可能性也会增加。

缓存内容的影响不仅仅影响使用 CDN 的用户。当无法重用缓存内容时,服务器基础设施可能需要从代价高昂的数据库查找中生成内容。更频繁访问的数据或预缓存页面通常可以表现更好。

避免多个页面重定向

导致 TTFB 偏高的一个常见原因是 重定向。当文档的导航请求收到响应,告知浏览器资源存在于另一个位置时,就会发生重定向。一次重定向肯定会给导航请求增加不必要的延迟,但如果该重定向指向另一个导致另一个重定向的资源,情况肯定会变得更糟——依此类推。这尤其会影响从广告或新闻通讯接收大量访问者的网站,因为它们通常通过分析服务进行重定向以进行衡量。消除您直接控制下的重定向有助于实现良好的 TTFB。

重定向有两种类型

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

您需要专注于消除同源重定向,因为这是您可以直接控制的事情。这将涉及检查您网站上的链接,以查看它们中的任何一个是否导致 302301 响应代码。通常,这可能是由于未包含 https:// 方案(因此浏览器默认使用 http://,然后重定向)或因为尾部斜杠未在 URL 中正确包含或排除。

跨域重定向比较棘手,因为这些通常超出您的控制范围,但请尽量避免多次重定向——例如,在共享链接时使用多个链接缩短器。确保提供给广告商或新闻通讯的 URL 是正确的最终 URL,以免在这些服务使用的重定向之外再添加另一个重定向。

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

一旦您制定了良好的 HSTS 策略,您可以通过 将您的网站添加到 HSTS 预加载列表 来加快首次访问源站的速度。

将标记流式传输到浏览器

浏览器经过优化,可以在标记流式传输时高效地处理标记,这意味着标记在从服务器到达时按块处理。这对于大型标记有效负载至关重要,因为这意味着浏览器可以增量解析标记块,而不是等待整个响应到达后再开始解析。

虽然浏览器非常擅长处理流式传输标记,但至关重要的是尽一切努力保持该流的畅通,以便这些初始标记位尽快发送出去。如果后端阻碍了事情,那就是一个问题。由于后端堆栈数量众多,因此本指南无法涵盖每个堆栈以及每个特定堆栈中可能出现的问题。

例如,React 以及其他可以 在服务器上按需渲染标记 的框架,都使用了同步方法进行服务器端渲染。但是,较新版本的 React 已经实现了 用于在渲染标记时流式传输标记的服务器方法。这意味着您不必等待 React 服务器 API 方法渲染整个响应后再发送它。

确保标记快速流式传输到浏览器的另一种方法是依赖 静态渲染,它在构建时生成 HTML 文件。由于完整文件立即可用,Web 服务器可以立即开始发送文件,并且 HTTP 的固有性质将导致流式传输标记。虽然这种方法并不适用于每个网站上的每个页面——例如那些需要动态响应作为用户体验一部分的页面——但对于那些不需要标记个性化为特定用户的页面来说,它可能是有益的。

使用 Service Worker

Service Worker API 可以对文档及其加载资源的 TTFB 产生重大影响。原因是 Service Worker 充当浏览器和服务器之间的代理——但是您的网站的 TTFB 是否受到影响取决于您如何设置 Service Worker,以及该设置是否符合您的应用程序要求。

  • 对资产使用 stale-while-revalidate 策略 如果资产在 Service Worker 缓存中——无论是文档还是文档所需的资源——stale-while-revalidate 策略将首先从缓存中提供该资源,然后在后台下载该资产并从缓存中提供它以供将来交互。
    • 如果您的文档资源不经常更改,则使用 stale-while-revalidate 策略可以使页面的 TTFB 几乎是即时的。但是,如果您的网站发送动态生成的标记(例如,根据用户是否经过身份验证而更改的标记),则此方法效果不佳。在这种情况下,您始终希望首先访问网络,以便文档尽可能最新。
    • 如果您的文档加载了一些频率变化的非关键资源,但获取过时的资源不会对用户体验产生太大影响——例如选择图像或其他非关键资源——则可以使用 stale-while-revalidate 策略大大减少这些资源的 TTFB。
  • 对客户端渲染的应用程序使用 应用 shell 模型 此模型最适合 SPA,其中页面的“shell”可以从 Service Worker 缓存中即时交付,页面的动态内容在页面生命周期后期填充和渲染。

对渲染关键资源使用 103 Early Hints

无论您的应用程序后端优化得多么好,服务器仍然可能需要做大量工作才能准备响应,包括昂贵的(但必要的)数据库工作,这会延迟导航响应的快速到达。这可能产生的影响是,某些后续的渲染关键资源可能会被延迟,例如 CSS 或(在某些情况下)在客户端渲染标记的 JavaScript。

103 Early Hints 标头 是一种早期响应代码,服务器可以在后端忙于准备标记时将其发送到浏览器。此标头可用于提示浏览器,在准备标记时,页面应开始下载渲染关键资源。对于 支持的浏览器,效果可能是更快的文档渲染 (CSS) 和更快的页面加载。

103 Early Hints 的一个缺点是,与缓存一样,它们可能会掩盖网站的“真实”TTFB。如果服务器基础设施速度较慢(要么是因为功率不足,要么是因为代码需要优化),那么当使用 103 Early Hints 时,这可能不太明显,因为 TTFB 看起来很快。使用 103 Early Hints 的网站应考虑测量实际服务器时间(通过 Server-TimingPerformanceNavigationTiming APIfinalResponseHeadersStart)。

结论

由于后端应用程序堆栈的组合如此之多,因此没有一篇文章可以概括您可以为降低网站的 TTFB 所做的一切。但是,这些是您可以探索的一些选项,以尝试使服务器端的事情稍微快一点。

与优化每个指标一样,方法大致相似:在现场测量您的 TTFB,使用实验室工具深入研究原因,然后尽可能应用优化。并非这里的每一种技术都可能适用于您的情况,但有些会适用。与往常一样,您需要密切关注您的现场数据,并根据需要进行调整,以确保最快的用户体验。

英雄图片由 Taylor Vick 提供,来源:Unsplash。