Web Performance

为什么你的 Time to First Byte 很慢,以及该如何处理

TTFB 不是单一的 bug。它是由 DNS、连接建立、CDN 路由、服务器工作、缓存未命中,有时还有一条缓慢的数据库查询共同造成的可见延迟。

The Wux Webtools Team The Wux Webtools Team 10 分钟阅读 人工智能辅助,人工审核
A simplified network path from a browser to a CDN and origin server showing points where latency can occur.
目录
  1. 先弄清 TTFB 实际测量的是什么
  2. 什么样的 TTFB 算慢?
  3. 在不止一个地方测量
  4. 1. 浏览器开发者工具
  5. 2. 来自多个地区的合成测试
  6. 3. 真实用户监控或服务器日志
  7. TTFB 缓慢的常见原因
  8. 你的 HTML 没有被缓存
  9. 你的 CDN 只缓存资源
  10. 你的服务器在响应前做了太多事
  11. 数据库查询缓慢或不可预测
  12. 你的应用存在冷启动
  13. 重定向浪费了第一次请求
  14. 一个实用的调试顺序
  15. Step 1: 测试主文档,而不只是整个页面
  16. Step 2: 对比地区
  17. Step 3: 检查响应头
  18. Step 4: 检查源站时序
  19. Step 5: 修复已确认的最大延迟
  20. 通常有效的修复方法
  21. 在边缘缓存公开 HTML
  22. 将非关键工作移出请求路径
  23. 减少后端依赖链
  24. 将计算放得离用户更近
  25. 让重定向保持简单
  26. 不要这样做
  27. 冷静版计划

先弄清 TTFB 实际测量的是什么

Time to First Byte,通常简称为 TTFB,指的是浏览器请求某个资源到收到响应第一个字节之间的时间。

这听起来像是一个服务器指标,但它并不只是服务器指标。TTFB 包含多个步骤:

  • DNS 查询,如果主机名尚未解析
  • TCP 连接建立
  • HTTPS 的 TLS 协商
  • 请求传输到服务器或 CDN 边缘节点的时间
  • 服务器上的排队和处理
  • 响应传回浏览器的时间

因此,TTFB 高可能意味着你的后端很慢。也可能意味着用户离你的源站很远、CDN 配置不当、缓存持续未命中,或服务器花了太长时间决定要发送什么。

这很重要,因为 TTFB 位于加载链路的开端附近。如果 HTML 文档到达得晚,浏览器也会更晚发现 CSS、JavaScript、字体和图片。即使前端优化做得很好,如果第一个文档响应耗时 1.5 秒,用户仍然会感觉很慢。

什么样的 TTFB 算慢?

没有一个通用数字适用于所有站点、地区和架构。不过,实用阈值仍然有帮助。

Google 的 web.dev 指南将低于 800 ms 的 TTFB 归为良好,800–1800 ms 需要改进,高于 1800 ms 则被视为较差。对于靠近用户提供服务且缓存良好的营销页面,你通常可以做到远好于这个数字。对于执行动态工作的复杂认证后台,可接受的数字可能更高,但它仍应当是可以解释的。

重要的习惯是对这个数字进行分段。900 ms 的全球平均 TTFB 可能掩盖了这样的事实:靠近 CDN 边缘节点的用户响应为 150 ms,而另一个地区的用户响应为 2200 ms。同样,你的首页可能表现良好,而搜索页、分类页或登录后页面却在悄悄让用户痛苦。

在不止一个地方测量

不要仅凭一次 Lighthouse 运行来诊断 TTFB。Lighthouse 很有用,但它只是来自一个环境的一次测试。如果你刚开始解读它,可以先冷静阅读如何在不恐慌的情况下阅读 Lighthouse 报告——核心经验是区分实验室信号与真实现场情况。

对于 TTFB,你至少需要三个视角:

1. 浏览器开发者工具

打开 Network 面板,禁用缓存后重新加载,并检查主文档请求。时序拆分会显示 DNS、连接、TLS、等待和下载阶段。“waiting” 阶段通常就是人们所说的后端时间,尽管它也可能包含上游延迟。

2. 来自多个地区的合成测试

从靠近和远离用户的位置运行测试。如果 TTFB 在一个地区低、在另一个地区高,在重写应用代码之前,应先怀疑地理位置、CDN 路由、源站位置或缓存覆盖范围。

3. 真实用户监控或服务器日志

现场数据会告诉你真实用户在不同设备、网络和会话中的体验。服务器日志可以告诉你源站是否快速生成了响应。客户端观测到的 TTFB 与源站处理时间之间的差值,往往正是 CDN 和网络问题出现的地方。

TTFB 缓慢的常见原因

你的 HTML 没有被缓存

这是内容站点和电商站点最常见的问题。静态资源被积极缓存,但 HTML 文档——浏览器最先需要的东西——却在每次请求时生成。

有时这是必要的。但很多时候并不是。

如果一个公开页面每天只变化几次,它可能不应该要求每位匿名访客都触发一次全新的数据库渲染。应在合适的地方使用整页缓存、边缘缓存、静态生成或 stale-while-revalidate 模式。

检查响应头中是否有 Cache-ControlCDN-Cache-StatusAgeVarySet-Cookie 等信号。一个给每位访客都发送唯一 cookie 的页面,可能会意外地让自己无法被缓存。如果你需要一种实用方式来理解这一层,我们关于在生产环境中调试重定向和 HTTP 头的指南中的调试习惯可以直接用于 TTFB 工作。

你的 CDN 只缓存资源

许多团队添加 CDN 后,就以为性能工作已经完成。但如果 CDN 只服务图片、CSS 和 JavaScript,第一个 HTML 请求可能仍然会一路传到单一源站服务器。

对于用户都在本地的本地企业站点,这可能没问题。对于国际受众,这就不行了。用户离源站越远,在后端工作开始之前你要支付的延迟就越多。

面向 TTFB 的良好 CDN 配置通常意味着:

  • 在安全的情况下缓存公开 HTML
  • 尊重认证页面或个性化页面的有意绕过规则
  • 避免不必要的 Vary 头将缓存切得过细
  • 使用缓存清除或重新验证,而不是完全禁用缓存
  • 确认边缘节点实际在提供命中,而不是转发每一个请求

CDN 不是魔法。它是缓存和路由层。要按这个定位来对待它。

你的服务器在响应前做了太多事

缓慢的后端路径可能来自许多小延迟:数据库查询、API 调用、模板渲染、功能开关检查、认证、个性化、日志记录和冷启动。

最糟糕的模式是串行依赖工作。例如:

  1. 获取页面数据
  2. 然后获取相关产品
  3. 然后获取价格
  4. 然后调用推荐服务
  5. 然后渲染 HTML

如果每一步都等待前一步完成,TTFB 会很快增长。并行化相互独立的工作,将非关键调用移出首次响应,并缓存开销高的结果。

一个有用的规则是:如果用户不能立即看到或使用该结果,它很可能不应该阻塞第一个字节。

数据库查询缓慢或不可预测

数据库经常造成 TTFB 问题,因为它们在开发环境中表现良好,在真实流量下却表现糟糕。缺失索引、大型 join、N+1 查询、锁竞争和过大的结果集,最终都会表现为“服务器很慢”。

这里不要靠猜。为慢请求捕获查询耗时。查看 p95 和 p99,而不仅仅是平均值。某个页面通常在 120 ms 内响应,但偶尔阻塞 4 秒,仍然会造成糟糕的用户体验。

常见修复包括:

  • 添加或修正索引
  • 移除 N+1 查询模式
  • 缓存读密集数据
  • 对大型查询进行分页
  • 将报表或分析查询从请求时移走
  • 为下游调用设置合理的超时

你的应用存在冷启动

Serverless 和容器化平台可以很优秀,但当流量呈突发状态或区域资源配置不足时,冷启动会伤害 TTFB。

如果空闲后一条首个请求明显慢于后续请求,就应调查冷启动。你可能需要预置并发、更小的包、更少的启动依赖、预热函数,或为延迟敏感路由采用不同的部署形态。

这不是反对 serverless。它反对的是假装运行时模型是不可见的。

重定向浪费了第一次请求

重定向会在浏览器收到最终文档之前增加一次额外的请求-响应周期。从 http://https:// 的一次重定向对于旧链接可能无法避免,但重定向链是浪费的。

常见链路包括:

  • http://example.comhttps://example.comhttps://www.example.com
  • 协议规范化之后再进行尾部斜杠规范化
  • 在缓存查找之前进行地域或语言重定向
  • 旧活动链接通过多个 URL 跳转

在可能的情况下修正源链接,合并重定向规则,并让规范 URL 直达。重定向时间并不总是计入最终请求的 TTFB,但用户仍然要为它付出时间。

一个实用的调试顺序

当 TTFB 看起来很慢时,按这个顺序来。它可以避免一个常见错误:在确认缓存和路由行为之前就先优化应用代码。

Step 1: 测试主文档,而不只是整个页面

找到 HTML 文档的请求。记录总 TTFB 和时序拆分。在有无浏览器缓存的情况下重复测试。如果相关,还要测试公开页面、动态页面和登录后页面。

Step 2: 对比地区

从多个地理位置运行同一个 URL。如果慢的地区与到源站的距离相关,应优先处理 CDN 和边缘缓存。如果每个地区都慢,就查看后端处理和源站容量。

Step 3: 检查响应头

查看缓存头、cookie、Age、CDN 状态和 Vary。缺失 Age 头或重复缓存未命中都是线索。公开 HTML 上宽泛的 Vary: Cookie 头通常是缓存杀手。

Step 4: 检查源站时序

添加服务器时序检测。Server-Timing 头可以暴露数据库时间、渲染时间和上游 API 时间等后端阶段。即使是简单标签也很有用:

Server-Timing: db;dur=82, render;dur=41, api;dur=210

现在,你的浏览器时序可以显示服务器是否在真实工作上花了 300 ms,或者延迟是否发生在请求到达应用之前。

Step 5: 修复已确认的最大延迟

这听起来显而易见,但团队常常修复熟悉的问题,而不是测量出来的问题。如果缓存未命中占主导,就修复缓存。如果数据库占主导,就修复查询。如果 TLS 和连接建立对全球用户占主导,就修复路由、CDN 覆盖或源站地理位置。

前端工作仍然重要。字体、图片和 JavaScript 会影响 HTML 到达之后发生的事情。但它们不能替代快速的首次响应。如果你也在处理渲染性能,在许多站点上,Web 字体仍然是最容易获得的性能收益之一,因为它们影响文档到达后文本多快可用。

通常有效的修复方法

在边缘缓存公开 HTML

对于营销页面、文档、博客、落地页和分类页,边缘缓存通常是改善 TTFB 的最大手段。如果内容频繁变化,可以使用较短的 TTL。如果缓存后台刷新时允许内容略微过期,可以使用 stale-while-revalidate。

要小心个性化。如果页面按货币、语言、登录状态或实验组变化,应明确定义这些变体。意外的逐用户变化会摧毁缓存效率。

将非关键工作移出请求路径

发送邮件、分析增强、推荐生成、webhook 调用和重日志记录,极少应该阻塞第一个字节。把它们放进队列,或在响应开始后运行。

减少后端依赖链

并行化独立调用。缓存慢 API 的响应。设置超时。为有帮助但非必要的服务设计兜底内容。

一个缓慢的推荐组件不应该拖慢整个产品页面。

将计算放得离用户更近

如果你的用户遍布全球,而源站只在一个区域,延迟就是结构性的。CDN 缓存可以为公开内容隐藏其中很大一部分。对于动态内容,可以考虑区域化部署、对合适路由进行边缘渲染,或将 API 移近受众。

让重定向保持简单

用一次跳转完成 URL 规范化。更新内部链接,让用户和爬虫直接到达最终目标。审计旧活动 URL 和平台迁移。重定向容易被忽视,因为它们正常工作时是不可见的,但它们仍然消耗时间。

不要这样做

不要为每条路由追求完美的 TTFB 数字。一个执行真实计算的认证报表,不会像缓存的博客文章那样表现。

不要把平均 TTFB 作为唯一指标。百分位数很重要。地理位置很重要。页面类型很重要。

不要假设有了 CDN 就意味着 HTML 已经被缓存。要验证它。

也不要把 TTFB 与产品决策割裂开来。个性化、实验、实时库存和第三方服务都有延迟成本。有些值得。有些只是习惯。

<!-- tool-cta:start -->

💡 试试这个: 诊断 TTFB 时,Get Headers 会显示缓存状态、服务器耗时和重定向,这些信息通常能解释延迟来自哪里。

<!-- tool-cta:end -->

冷静版计划

一旦你不再把 TTFB 当作模糊的“服务器问题”,缓慢的 TTFB 通常是可以修复的。测量文档请求。按地区和页面类型分段。检查响应头。对比客户端时序和源站时序。然后修复已确认的最大瓶颈。

大多数站点不需要奇异架构。它们需要的是更少可避免的缓存未命中、更少阻塞性的后端工作、更干净的重定向,以及更清楚地知道在发送第一个字节之前必须发生什么。

常见问题

TTFB 是 Core Web Vitals 指标吗?
不是。TTFB 不是 Core Web Vitals 之一,但它会强烈影响 Largest Contentful Paint 等指标,因为在发现文档及其依赖资源之前,浏览器无法渲染重要内容。
好的 TTFB 目标是多少?
作为一般基准,web.dev 认为低于 800 ms 是良好。对于缓存的公开页面,许多团队可以把目标定得更低。对于复杂的认证路由,应关注一致性、百分位数,以及延迟是否合理。
添加 CDN 会自动修复 TTFB 吗?
不一定。只有当 CDN 降低了路由延迟或提供了缓存响应时,它才会改善 TTFB。如果每个 HTML 请求都被转发到源站,你的 CSS 和图片可能很快,但文档仍然很慢。
JavaScript 优化能改善 TTFB 吗?
对于传统服务器端渲染页面,通常不能直接改善。JavaScript 会影响响应开始后的解析、渲染和交互性。TTFB 主要关注的是将第一个响应字节送到浏览器。
为什么我的 TTFB 只对登录用户很慢?
登录后页面更难缓存,因为它们是个性化的。那里的 TTFB 缓慢通常来自数据库查询、权限检查、API 调用、会话处理,或无法在用户之间共享的服务器端渲染工作。

来源与进一步阅读

  1. web.dev: Optimize Time to First Byte
  2. MDN Web Docs: PerformanceResourceTiming.responseStart
  3. W3C: Server Timing
  4. RFC 9111: HTTP Caching
关于作者
The Wux Webtools Team

最后更新:

继续阅读