接口耗时分解巡检
「接口慢」只是表象,实际可能慢在 DNS、TCP 握手、TLS 协商、服务端首字节或内容下载任何一环。curl 的 -w 能把这些阶段分别输出为数字,一次请求就能把责任范围切到具体环节,是性能巡检里性价比最高的手段之一。批量跑一轮再排序,就能挑出最值得优化的目标。
基本信息
| 适用场景 | 接口或页面性能瓶颈定位、批量巡检、发布前后对比 |
|---|---|
| 核心手段 | curl -w 输出分段计时变量,配合 -o /dev/null 只看时间 |
| 常用变量 | time_namelookup、time_connect、time_appconnect、time_starttransfer、time_total |
| 适用范围 | Linux / macOS,curl 7.x 以上均可 |
典型使用场景
- 用户反馈某接口慢,先确认慢在哪个阶段再找人
- 发布前后各跑一轮,量化对比是否真的变快
- 批量巡检多个站点,挑出耗时最长的几个重点看
- CDN 与回源对比:首字节时间差异能直接反映回源问题
- 排查 TLS 握手是否成为主要耗时
单次分解
单次分解
curl -sS -o /dev/null -w 'dns=%{time_namelookup} conn=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total} size=%{size_download}\n' https://example.com/ # 一次请求拆出五段耗时
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' --max-time 10 https://example.com/ # 加超时上限,避免巡检卡死
for i in 1 2 3; do curl -sS -o /dev/null -w '%{time_total}\n' https://example.com/; done # 重复三次看抖动批量对比
批量对比
while read -r url; do
curl -sS -o /dev/null --max-time 10 -w '%{time_total} %{time_starttransfer} %{time_connect} %{http_code} ' "$url"
echo "$url"
done < urls.txt | sort -rn | head # 按总耗时倒序,优先看最慢的分段指标读法
| 变量 | 含义 | 异常时的判断 |
|---|---|---|
| time_namelookup | DNS 解析用时 | 偏大说明解析慢或首次查询未命中缓存 |
| time_connect | 到 TCP 握手完成(含解析) | 与解析值相减才是握手本身 |
| time_appconnect | TLS 握手完成 | 明显偏大说明握手或证书链有问题 |
| time_starttransfer | 首字节到达 | 偏大通常是服务端处理慢 |
| time_total | 整体耗时 | 与首字节之差即内容传输时间 |
| size_download | 下载字节数 | 配合耗时判断是内容大还是链路慢 |
time_connect 已包含 time_namelookup,算 TCP 握手本身要用差值;同理 appconnect 包含 connect,starttransfer 包含前面所有阶段。
排查顺序建议
- 先看 time_total 是否真的超出预期,避免拿主观感受当指标
- 再看 time_starttransfer 与 time_total 的关系:首字节就慢是服务端问题,首字节快而整体慢是传输或内容体积问题
- 首字节也快、整体也快但仍报慢,检查是否走了多跳重定向,加上 -L 后各阶段会累加
- DNS 与 TLS 阶段大,优先怀疑解析与证书链而不是后端代码
- 同一目标重复三次取中位数,再与历史基线对比,单次数据不做结论
加 -L 跟随重定向后,计时变量覆盖的是整条链路的总和,需要配合 %{num_redirects} 一起看,否则会把多次请求的耗时算成一次。