网站变慢时,先确定影响范围,再把一次加载拆成 DNS、连接、TLS、等待首字节、正文下载和浏览器渲染。只有定位到变慢的区间,服务器、CDN、数据库和前端优化才有明确对象。

从用户范围确认到 curl 分段耗时、网络瀑布、服务器指标和浏览器主线程的性能排查路径
curl 判断网络和首字节耗时;服务器指标与浏览器时间线分别定位后端和渲染问题。

先锁定受影响的 URL、用户和时间

排查前记录具体 URL、发生时间和复现条件:

  • 具体 URL,而不是只写域名;
  • 发生时间和时区;
  • 用户地区、网络和设备;
  • 登录状态、缓存状态和操作路径;
  • 慢是持续发生、首次访问发生,还是偶发尖峰。

只有一个用户受影响时,优先排查本地 DNS、代理、网络、浏览器扩展和缓存。多个地区同时变慢,再检查 CDN、入口和源站。某个页面或操作慢,通常要进入该路由的接口、查询和第三方依赖。

用 curl 拆开网络和首字节时间

curl -sS -o /dev/null \
  -w $'code=%{http_code}\nremote=%{remote_ip}\ndns=%{time_namelookup}\nconnect=%{time_connect}\ntls=%{time_appconnect}\nttfb=%{time_starttransfer}\ntotal=%{time_total}\n' \
  https://example.com/path

这些值是从请求开始累计的时间。单段耗时需要用相邻值相减:

区间近似计算异常时优先检查
DNStime_namelookup本机解析器、权威 DNS、记录和缓存
TCPtime_connect - time_namelookup路由、丢包、入口地域和端口
TLStime_appconnect - time_connect网络往返、证书链、协议和会话复用
首字节等待time_starttransfer - time_appconnectCDN 回源、代理、应用、数据库和外部 API
正文下载time_total - time_starttransfer响应体积、压缩、带宽和限速

字段语义以 curl --write-out 文档(在新标签页打开)为准。连接复用、HTTP/3、代理和本地合成 DNS 会改变各阶段表现;输出中的 remote_ip 如果是代理地址,就不能把这组数据当成用户到源站的公网基准。

在同一地点连续测量多次,再换一个地区或网络对照。比较中位数和高分位趋势,不要用最快的一次代表日常体验。

TTFB 高时继续拆 CDN 和源站

TTFB 是收到响应第一个字节之前的总时间,不是后端函数耗时。web.dev 对 TTFB 的说明(在新标签页打开)把重定向、DNS、连接、TLS 和服务端响应都包含在这段等待中。

对同一个公开资源连续请求:

curl -sS -D /tmp/first.headers -o /dev/null https://cdn.example.com/image.webp
curl -sS -D /tmp/second.headers -o /dev/null https://cdn.example.com/image.webp

grep -Ei '^(age|cache-control|etag|server|via|x-cache|cf-cache-status):' \
  /tmp/first.headers /tmp/second.headers

缓存 HIT 快、MISS 慢,说明瓶颈更可能在回源或源站。HIT 和 MISS 都慢,要检查边缘节点、用户到 CDN 的网络,以及响应是否真的经过预期入口。直连源站测试必须保留 Host 和 SNI,不能用裸 IP 请求得出结论。

在 Network 面板找到最慢的请求

Chrome DevTools Network(在新标签页打开)会记录文档、CSS、JavaScript、字体、图片和接口请求。录制前记下这些条件:

  • 是否勾选 Disable cache;
  • 网络和 CPU 是否限速;
  • 是否清空站点数据;
  • 设备、浏览器版本和视口;
  • 录制的是首次访问还是重复访问。

按 Duration、Size 和 Initiator 排序,先找:

  • 文档请求本身的 Waiting/TTFB;
  • 阻塞渲染的 CSS 和字体;
  • 大图和错误尺寸的图片;
  • 串行接口和重复请求;
  • 第三方脚本、广告、统计和客服组件;
  • 404、重定向链和请求重试。
DNS、TLS、TTFB、下载、LCP 和交互延迟分别映射到 DNS、入口、后端、资源和浏览器主线程所有者的图
瀑布图负责找到慢请求;服务端指标和 Performance trace 负责解释它为什么慢。

HTML 快但页面仍慢时看渲染

文档 TTFB 正常,页面仍长时间空白或主要内容迟迟出现,问题已经从服务端等待转到资源和渲染。

LCP 常见候选是首屏大图、标题块或海报。检查候选资源是否在 HTML 中及时发现、是否被懒加载、是否下载过大,以及 CSS 或 JavaScript 是否延迟它显示。web.dev 的 LCP 优化指南(在新标签页打开)把 TTFB、资源发现、资源下载和元素渲染延迟分开处理。

Performance 面板再检查:

  • 超过 50 ms 的长任务;
  • 大量脚本解析、执行和重复布局;
  • 字体加载造成的文字延迟或布局变化;
  • 图片缺少尺寸导致的重排;
  • 主线程被第三方脚本长期占用。

减少图片体积不能修复慢 SQL;提高数据库索引也不会缩短一个 4 MB 首图的下载。先用时间线确认耗时发生在资源下载、数据库还是浏览器主线程。

服务器日志与指标要对齐同一时间窗口

服务器排查至少把入口日志、容器状态和主机指标对齐到用户发生问题的时间:

docker compose ps
docker stats --no-stream
ss -lntp
journalctl -u caddy --since '10 minutes ago' --no-pager

应用层继续查看请求耗时、状态码、数据库慢查询、连接池等待、缓存命中和外部 API 时间。平均值会掩盖尖峰,至少保留 p50、p95、p99 和错误率;没有统一 request ID 时,也要用时间、路径和上游状态对齐日志。

证据更可能的瓶颈
主机 CPU 持续满、运行队列升高计算或进程争抢
内存不足并发生 swap 或 OOM工作集过大、泄漏或限额过低
磁盘 await、util 持续升高日志、数据库或卷 I/O
应用快但代理 upstream time 高网络、协议、连接池或日志口径错误
应用与 SQL 同时出现长尾查询、锁、连接池或数据量
只在外部 API 调用时变慢第三方延迟、超时和重试放大

修复后用同一条件复测

复测使用相同 URL、地区、网络、设备、缓存状态和采样方式。比较修复前后的分段时间、瀑布图、服务器高分位和错误率;只比较两个 Lighthouse 总分,无法确认瓶颈是否已经消失。

复测时,把异常阶段、相关组件、改动内容和指标变化放在同一条时间线上,同时检查是否带来新的缓存或错误风险。

如果入口直接返回 502 或 504,先沿反向代理到上游检查网络、端口和超时,见502 和 504 怎么排查

常见问题

网站打开慢应该先查服务器吗?

不一定。先拆 DNS、连接、TLS、TTFB、下载和渲染。证据指向首字节等待或服务端资源后,再进入服务器排查。

TTFB 高就代表后端代码慢吗?

不代表。TTFB 还包含重定向、DNS、连接、TLS、CDN 回源和代理等待,需要用相邻时间差与入口日志继续拆分。

Lighthouse 跑一次能定位性能问题吗?

不能。单次实验室结果只提供线索,必须保留测试条件,并结合真实用户数据、网络瀑布和服务器指标。

首页很快但用户仍说网站慢,应该查什么?

检查用户实际 URL、地区、设备、登录状态和时间窗口。详情页接口、第三方脚本或大图可能只在特定路径出现。

怎样区分 CDN 慢和源站慢?

比较同一 URL 的 HIT、MISS 和源站结果,并核对 Age、ETag、正文哈希与入口日志。缓存命中快而回源慢,瓶颈通常不在浏览器渲染。