LabHub
学习 学习路径 课程

网络排障

用 curl -w 点出慢在哪一段

在 LabHub 中继续学习

一句话总结

curl -w 的计时字段可以把一次请求拆成名称解析、建立连接、TLS、首字节、完整请求五个阶段。把“很慢”这种报障改写成具体的阶段名称,是诊断的起点。

对比图: 名称解析、建立连接、TLS、首字节、完整请求 · 从请求开始计算的累计时间 · 不修改 DNS 的情况下 · 直接测试负载均衡器后的后端时,如果 Host 不一致,比较本身就没有意义。

为什么需要这些计时数据

“API 很慢”几乎没有提供任何信息。名称解析慢、TLS 握手慢和后端查询慢是完全不同的问题,负责的团队也不同,但在用户眼中,它们看起来都只是“很慢”。

它是如何工作的

一行命令就足够了。

curl -o /dev/null -s -w \
 'dns=%{time_namelookup} conn=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total} code=%{http_code}\n' \
 https://api.example.com/health

每个字段都是从请求开始计算的累计时间,因此,各阶段耗时需要通过减法得到。

阶段 计算方法 耗时过长时应怀疑什么
名称解析 time_namelookup 解析器、search 域、ndots
TCP 连接 time_connect - time_namelookup 防火墙、距离、SYN 重传
TLS time_appconnect - time_connect 证书链、OCSP 查询、协议协商
服务器处理 time_starttransfer - time_appconnect 应用程序、数据库
响应体传输 time_total - time_starttransfer 带宽、响应大小

阅读要领是:connect 一直增长到超时,应检查防火墙;只有 appconnect 很长,应检查 TLS;appconnect 很快、只有 ttfb 很长,则应检查应用程序或数据库。

下面这些选项也是诊断时不可缺少的。

curl -v https://api.example.com/health                 # 요청/응답 헤더 전체
curl --resolve api.example.com:443:10.0.1.50 https://api.example.com/health
curl -H 'Host: api.example.com' http://10.0.1.10:8080/health
curl -sD - -o /dev/null https://api.example.com/       # 헤더만
curl -L --max-redirs 10 -v https://example.com 2>&1 | grep '< [Ll]ocation'

--resolve 可以在不修改 DNS 的情况下,让指定名称指向特定 IP。部署前使用真实名称测试新服务器时,它必不可少。-H 'Host:' 则用于直接连接 IP,同时保持原有的虚拟主机路由。直接测试负载均衡器后的后端时,如果 Host 不一致,比较本身就没有意义。

-I 会发送 HEAD 请求。如果服务器对 HEAD 采用不同的处理方式,或者完全禁用了 HEAD,其结果就会与 GET 不同。存在疑问时,使用 -sD - -o /dev/null 发送 GET、只查看响应头更加安全。

常见误诊

看到 502 就断定“上游服务挂了”。 502 表示代理从上游收到了无效响应。如果响应头大于代理缓冲区,即使后端完全正常也会产生 502。而且,增加超时时间对 502 没有作用——那是 504 的处理方法。

只看有效期就放过证书。 浏览器会缓存中间证书,所以开发者的电脑上可能看起来正常;服务器之间的调用没有缓存,就会失败。必须统计证书链数量进行确认。

echo | openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts 2>/dev/null | grep -c 'BEGIN CERTIFICATE'

在应用程序中寻找重定向循环的原因。 通常是 TLS 终止点与应用程序的 HTTPS 强制逻辑彼此不知道对方的存在。应传递 X-Forwarded-Proto,并在边界处覆盖该值。

还必须准确理解重定向状态码。302 可以把 POST 改成 GET,303 强制使用 GET,而 307/308 保留原请求方法。 强制协议跳转适合使用 308,表单提交后的页面跳转则适合使用 303。

实际工作中会遇到的情况

“curl 正常,只有浏览器失败。” 此时应该检查浏览器特有的规则,而不是服务器本身。候选原因包括 CORS 预检、SameSite Cookie、混合内容阻止、HSTS,以及 HTTP/2 连接合并(421)。curl 完全不会应用这些规则。

下一个实验要做什么

启动诊断用 HTTP 服务器,依次提取状态码、响应头、重定向、虚拟主机和计时信息。其中的重点是使用 --resolve,在不依赖 DNS 的情况下通过名称建立连接。