七个阶段,每一段都可能出问题
把一次请求拆开看,排障时才有抓手。从输入网址到看到页面,大致经过:URL 解析 → DNS 解析 → 建立连接(TCP + TLS)→ 发送请求 → 服务端处理 → 接收响应 → 渲染与子资源加载。多数「网站慢」的抱怨,都能定位到其中某一段。
逐段拆解
- URL 解析:协议、主机、端口、路径与查询串被拆开,端口未写时使用协议默认值(HTTP 80 / HTTPS 443);
- DNS 解析:浏览器缓存 → 系统缓存 → hosts → 递归解析器 → 权威服务器,最终拿到 A 或 AAAA 记录;
- 建立连接:TCP 三次握手,HTTPS 还要额外完成 TLS 握手(验证证书、协商会话密钥);
- 发送请求:请求行、请求头与请求体;注意 Content-Length、分块传输与 Cookie 体积;
- 服务端处理:路由、鉴权、业务逻辑与数据库访问,这里通常是耗时大头;
- 接收响应:状态码决定后续动作——重定向、读缓存还是报错;
- 渲染与子资源:HTML 解析后继续拉取 CSS、JS、图片与接口,每一项又是一轮新的请求。
耗时分布怎么看
| 阶段 | 典型耗时 | 常见优化 |
|---|---|---|
| DNS | 几毫秒~数百毫秒 | DNS 预解析、减少域名数量、合理 TTL |
| TCP / TLS | 1~3 个 RTT | 连接复用、会话复用、升级 TLS 1.3 |
| 服务端处理(TTFB) | 取决于后端 | 缓存、SQL 优化、边缘计算 |
| 内容传输 | 与体积成正比 | 压缩、精简资源、流式输出 |
| 渲染与子资源 | 取决于前端结构 | 减少关键路径资源、懒加载 |
排障顺序
- 先看状态码:4xx 多为请求问题,5xx 为服务端问题,3xx 要数清跳数;
- 再看TTFB:偏高说明服务端慢或链路绕行;
- 打开开发者工具的 Timing 面板,逐段确认卡在哪一阶段;
- 用命令行复核,排除浏览器因素(见下)。
一个够用的命令行模板
curl -sS -o /dev/null -w \
'dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} \
ttfb=%{time_starttransfer} total=%{time_total} code=%{http_code}\n' \
https://example.com/
把这几个时间按顺序读一遍即可定位:dns 高查解析,connect 高看链路,tls 高看握手,ttfb 高看服务端,total 减 ttfb 大则是传输或体积问题。
实战排查:三个典型现象
- “首包很慢、之后正常”:优先看 DNS 与连接建立(冷启动),再确认是否命中缓存;多半是解析或握手成本,而非服务端。
- “TTFB 高但传输很快”:问题在服务端处理(数据库、下游调用),应查慢查询与外部依赖,而不是加大带宽。
- “总时长高、各阶段都不高”:多半是子资源过多或重定向链叠加,先数清请求数与跳数再优化。
常见问题
为什么第一次访问慢、之后快?DNS 缓存、连接复用与资源缓存共同作用的结果,冷启动慢属正常。HTTPS 一定比 HTTP 慢吗?握手多 1~2 个 RTT,但 TLS 1.3 与会话复用已将差距压得很小,换取的安全性更划算。重定向多了会怎样?每个 3xx 都是一次完整往返,应尽量减少重定向链,尤其不要 HTTP → HTTPS → 带 www 的多跳叠加。
每层的常见耗时位置
- DNS:首次解析通常 20–120ms,缓存命中可降到几乎为零;
- TCP + TLS:新建连接包含 1 个 RTT 握手与 1–2 个 RTT 的 TLS,是首屏延迟的大头,复用连接收益明显;
- 服务端:体现为 TTFB,包含排队、鉴权、数据库查询与下游调用;
- 传输:受带宽与拥塞窗口影响,大响应体在慢速网络下会显著拉长;
- 渲染:HTML 到达后还有解析、样式计算与脚本执行,关键资源应尽早发现。
可观测的埋点位置
- 浏览器侧:Navigation Timing 给出 DNS、连接、TTFB 与资源加载的分解;
- 网关侧:记录上游耗时与排队时长,区分“服务慢”与“排队久”;
- 应用侧:数据库与下游调用分别计时,避免把全部时间都算成“接口耗时”;
- 三段数据用同一个请求 ID 串起来,才能定位是链路哪一段的问题。
多路复用带来的变化
HTTP/2 之后,浏览器可以在一条连接上并发多个请求,连接建立成本被摊薄,域名分片不再必要;但同时要避免把关键资源全压在同一条连接上被队头阻塞。HTTP/3 把丢包影响限制在单个流内,弱网下的首屏体验通常更稳定。