2. 延迟分析基础:延迟的定义与分类
做性能优化这么多年,我最大的体会就是:你没法优化你测量不了的东西。延迟分析,说白了就是搞清楚“时间都去哪儿了”。
很多团队一上来就堆缓存、加机器,结果效果甚微。为什么?因为他们根本没找到真正的瓶颈在哪。今天我们就来聊聊延迟的基础——怎么定义它、怎么分类它、怎么找到它。
2.1 延迟到底是个啥?
延迟,英文叫 Latency。简单说,就是从发起请求到收到响应之间的时间差。
举个例子:你点了一个按钮,到页面出现反馈,这中间的时间就是延迟。但这里有个坑——延迟不等于响应时间。响应时间 = 延迟 + 处理时间。嗯,这个区别很重要。
核心公式:
总延迟 = 网络延迟 + 处理延迟 + I/O 延迟
响应时间 = 总延迟 + 业务处理时间
我在项目中遇到过不少同事,把“响应慢”直接等同于“代码慢”。其实很多时候,代码只跑了 5ms,网络却花了 200ms。你想想看,优化代码还有意义吗?
2.2 延迟的三大分类
我个人习惯把延迟分成三类:网络延迟、处理延迟、I/O 延迟。这三兄弟经常一起出现,但根因完全不同。
| 延迟类型 | 典型场景 | 常见量级 | 识别难度 |
|---|---|---|---|
| 网络延迟 | HTTP 请求、RPC 调用、数据库连接 | 1ms ~ 500ms | 中等 |
| 处理延迟 | CPU 计算、业务逻辑、序列化 | 0.1ms ~ 100ms | 较低 |
| I/O 延迟 | 磁盘读写、文件操作、内存换页 | 0.1ms ~ 10s | 较高 |
2.3 网络延迟的识别方法
网络延迟,说白了就是数据在“路上”花的时间。它受物理距离、带宽、网络拥塞等因素影响。
怎么识别?
- ping 命令:最基础的工具。ping 一下目标地址,看 RTT(往返时间)。如果 RTT 超过 100ms,基本可以确定网络是瓶颈。
- traceroute / tracert:看数据包经过了多少跳。跳数越多,延迟越高。我曾经排查过一个跨洲调用,发现竟然绕了 20 多跳,后来直接换了专线。
- Wireshark / tcpdump:抓包分析。看 TCP 握手时间、重传率。如果重传率超过 1%,网络质量堪忧。
小技巧:
用 curl -w "time_total: %{time_total}\n" 可以快速看 HTTP 请求的总耗时。配合 time_namelookup、time_connect 等参数,能拆解 DNS 解析、TCP 连接、TLS 握手等各阶段耗时。
2.4 处理延迟的识别方法
处理延迟,就是 CPU 在“干活”的时间。代码写得烂、算法复杂度高、锁竞争激烈,都会导致处理延迟飙升。
怎么识别?
- 火焰图(Flame Graph):我最爱的工具。它能直观展示 CPU 时间花在了哪些函数上。宽条就是热点,优先优化。
- perf / 性能剖析器:Linux 上用
perf top看实时热点。Java 用 Async Profiler,Go 用 pprof。 - 日志打点:在关键路径前后打日志,计算耗时差。注意,日志本身也有 I/O 开销,别打太多。
// 伪代码示例:打点测量处理延迟
long start = System.nanoTime();
processOrder(order);
long elapsed = System.nanoTime() - start;
if (elapsed > 100_000_000) { // 超过 100ms
logger.warn("processOrder 耗时过长: {} ms", elapsed / 1_000_000);
}
避坑指南:
我曾经在线上用 System.currentTimeMillis() 打点,结果发现打点本身占了 30% 的 CPU。后来改用 System.nanoTime(),精度更高,开销更小。记住:测量工具不能成为新的瓶颈。
2.5 I/O 延迟的识别方法
I/O 延迟,是数据在“读写”时花的时间。磁盘慢、网络慢、文件大,都会导致 I/O 延迟。它往往是系统中最隐蔽的瓶颈。
怎么识别?
- iostat:看磁盘的
await和svctm。如果await超过 10ms,磁盘可能扛不住了。 - iotop:看哪个进程在疯狂读写磁盘。有时候是日志进程在搞鬼。
- strace:跟踪系统调用。看
read、write、fsync的耗时。我遇到过一个问题,一个fsync竟然花了 2 秒,后来发现是磁盘快满了。
I/O 延迟的典型特征:
- CPU 利用率不高,但系统响应慢
- 磁盘利用率(%util)接近 100%
- 平均 I/O 队列长度(avgqu-sz)大于 1
2.6 三类延迟的关系与识别流程
这三类延迟不是孤立的。网络延迟可能导致处理延迟(等待数据),处理延迟可能导致 I/O 延迟(写日志)。所以,识别的时候要有套路。
下面这张图是我自己总结的识别流程,分享给你:
2.7 实战:一个典型的延迟分析案例
我记得有一次,线上一个接口响应时间从 50ms 飙升到 800ms。我按上面的流程走了一遍:
- 先看 CPU:CPU 利用率只有 20%,不高。排除处理延迟。
- 再看网络:ping 了一下数据库,RTT 只有 2ms。排除网络延迟。
- 最后看 I/O:iostat 一看,
await高达 200ms,磁盘利用率 99%。
根因找到了:数据库的磁盘是机械盘,而且快满了。后来换了 SSD,响应时间降到 60ms。你想想看,如果我一上来就去优化代码,那得白费多少功夫?
我的经验:
做延迟分析,别凭感觉。先看数据,再下结论。我见过太多人“觉得”是代码慢,结果一查是网络问题。工具不会骗人,但感觉会。
2.8 小结
延迟分析是性能优化的基本功。记住三点:
- 网络延迟:用 ping、traceroute、Wireshark 识别
- 处理延迟:用火焰图、perf、日志打点识别
- I/O 延迟:用 iostat、iotop、strace 识别
识别流程:先 CPU,再网络,最后 I/O。这个顺序能帮你少走弯路。