一、单行命令打印五个累计时间点
在终端执行下面这条命令(可将末尾 URL 换成任意你想测试的 HTTPS 域名):
curl -o /dev/null -s -w "dns: %{time_namelookup}s\ntcp: %{time_connect}s\ntls: %{time_appconnect}s\nttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" https://example.com
注意一个最容易踩的坑:curl 输出的五个变量全部是「从请求发起那一刻(0.000s)算起的累计时间」,而不是每个阶段单独的耗时。要想算出每一棒真正花了多少毫秒,需要做一次相邻相减:
| 阶段名称 | 差值计算公式 | 网络层真实动作与排障判据 |
|---|---|---|
| DNS 解析 | time_namelookup |
本地解析器查询域名耗时。若超过 50ms,优先检查本机 /etc/resolv.conf 或上游递归 DNS 是否绕远。 |
| TCP 握手 | connect - namelookup |
客户端发出 SYN 到收到 SYN+ACK 的耗时,直接反映客户端到节点机房的物理网络 1-RTT 基准延迟。 |
| TLS 握手 | appconnect - connect |
TLS 密钥协商与证书验证。开启 TLS 1.3 时约为 1 × RTT;若退回 TLS 1.2 且无会话复用,会膨胀到 2 × RTT。 |
| 首包等待 (TTFB) | starttransfer - appconnect |
等于 1 × RTT 传输加上服务端处理时长(网关反代 + 业务逻辑)。若 TCP 很短而此项偏长,可重点排查服务端处理或上游回源耗时。 |
| 正文下载 | total - starttransfer |
接收响应体字节耗时。大文件此项慢时,通常受限于 TCP 接收窗口或拥塞控制算法(如 Cubic 在丢包链路上的降速)。 |
二、连接复用对比:用一个 curl 命令连发两次请求
HTTP/1.1 默认开启 Keep-Alive,HTTP/2 则在单条 TCP+TLS 连接上多路复用。把同一个 URL 在一条 curl 命令里写两遍,就能亲眼看到连接复用省掉了多少时间:
curl -o /dev/null -s -w "Req#1 -> tcp:%{time_connect}s tls:%{time_appconnect}s total:%{time_total}s\n" https://example.com \
-o /dev/null -s -w "Req#2 -> tcp:%{time_connect}s tls:%{time_appconnect}s total:%{time_total}s\n" https://example.com
在跨洋链路上(例如往返 RTT 为 150ms 的场景),第一次新建连接时 TCP 与 TLS 1.3 握手合计需要约 2 × RTT(约 300ms);而紧接着的第二次请求因为直接复用了已打开的套接字,time_connect 和 time_appconnect 会直接显示为 0.000000s,省去了前两轮握手往返。这也是为什么在反代与上游之间配置长连接池(keepalive)能直接省掉重复建连开销。