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

了解如何针对 Time to First Byte 指标进行优化。

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

建议您足够快的服务器响应导航请求,以便第 75 百分位的用户得到的 FCP 在“良好”阈值以内。一般来说,大多数网站的 TTFB 都应不超过 0.8 秒

良好的 TTFB 值为 0.8 秒或更短,不良值大于 1.8 秒,两者之间的任何值都需要改进

如何衡量 TTFB

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

PageSpeed Insights 是一种简便方法,可获取 Chrome 用户体验报告中针对公开网站的实地信息和实验室信息。

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

PageSpeed Insights 真实用户数据

服务器响应时间审核日志中显示了一部分 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 开发者工具中网络标签页的时间面板中:

Chrome 开发者工具“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 中看起来可能不同,但缓存版本不会使用。

此外,较早或访问频率较低的内容可能不会被缓存,这可能会导致某些网页上的 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 的方式,以及该设置是否符合您的应用要求。

  • 针对资产使用 stale-while-revalidate 策略如果资源在 Service Worker 缓存中(无论是文档所需的文档还是资源),过时同时重新验证策略将首先从缓存中提供该资源,然后在后台下载该资源,并从缓存中提供该资源,以备将来的互动之用。
    • 如果您的某些文档资源不经常更改,使用过时的“同时重新验证”策略可以让页面的 TTFB 近乎即时。然而,如果您的网站发送动态生成的标记(例如,根据用户是否已通过身份验证而发生变化的标记),则上述方法就不适用了。在这种情况下,您始终需要首先连接到网络,以便尽可能地更新文档。
    • 如果您的文档加载了具有一定频率变化的非关键资源,但提取过时资源不会对用户体验(例如选择图片或其他不重要的资源)产生太大影响,则可以使用“同时重新验证”策略来大幅降低这些资源的 TTFB。
  • 尽可能使用流式 Service Worker 架构此 Service Worker 架构使用的方法将文档资源的部分存储在 Service Worker 缓存中,并在导航请求期间与内容部分合并。使用此 Service Worker 模式所产生的结果是,您的导航将非常快速,同时从网络下载较小的 HTML 载荷。虽然这种 Service Worker 模式并不适用于所有网站,但对于可以使用它的网站来说,文档资源的 TTFB 时间实际上几乎可以说是即时的。
  • 针对客户端渲染的应用使用 App Shell 模型此模型最适合 SPA,在这种 SPA 中,可通过 Service Worker 缓存立即传递网页的“外壳”,并且会在网页生命周期的后期填充和呈现网页的动态内容。

103 Early Hints 用于渲染关键资源

无论应用后端的优化程度如何,服务器仍然可能要完成大量工作来准备响应,包括昂贵(但必须)的数据库工作,它们会延迟导航响应尽快到达。这样做的潜在影响是,一些后续渲染关键资源可能会发生延迟,例如 CSS,或在某些情况下,即在客户端上渲染标记的 JavaScript。

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

总结

由于后端应用堆栈的组合非常多,因此没有哪一篇文章能够概括为降低网站 TTFB 所采取的所有方法。不过,您可以探索以下一些选项,尝试让服务器端的运行速度稍快一些。

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

主打图片:Taylor Vick,来自 Unsplash。