把「慢」这个词换成数字
一句话总结
只说“很慢”无法修复任何问题。把它改写成什么功能、从何时开始、慢多少、影响百分之多少,调查范围立刻会缩小到原来的十分之一。
为什么需要它
问题报告通常是这样提交的:“最近系统很慢。”
这时立即登录服务器查看 CPU,是最常见的错误。CPU 为 30% 时,人们会以“看起来正常”结束调查;CPU 为 90% 时,又会错误地以“就是 CPU 导致的”结束调查。两种结论都不是答案。
首先应该询问四个问题。
| 问题 | 为什么要问 | 答案能够缩小的范围 |
|---|---|---|
| 哪个页面或功能? | 很少出现全部功能都慢 | 代码路径 |
| 从何时开始? | 与部署、配置变更对照 | 原因发生的时间点 |
| 慢多少?(过去 2 秒,现在 20 秒) | 区分慢 10 倍还是慢 10% | 问题性质 |
| 总是发生,还是偶尔发生? | 区分平均问题与尾部问题 | 调查方法 |
第四个问题尤其重要。**一直很慢和偶尔很慢的原因不同。**一直很慢通常来自结构问题(查询、N+1、同步调用);偶尔很慢通常来自竞争(锁、连接池、GC、磁盘)。把两类问题混在一起观察,只会被平均值掩盖,什么都看不出来。
拆分各个区段
把一个请求经过的路径分段,并测量每个区段的耗时。
클라이언트 → [네트워크] → 웹서버 → [앱] → [DB] → 앱 → 웹서버 → 클라이언트
即使没有专用测量工具,也可以只用一个 curl 拆分区段。
curl -o /dev/null -s -w \
'dns=%{time_namelookup} conn=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' \
https://example.com/slow-page
dns较大 → 名称解析问题,包括解析器配置、缓存未命中。conn较大 → TCP 连接问题,包括路由、防火墙、SYN 等待。tls较大 → 握手问题,包括证书链、OCSP 查询。ttfb较大而total - ttfb较小 → 服务器思考的时间,即应用或数据库。total - ttfb较大 → 正文传输问题,可能是响应过大或带宽不足。
仅凭这五个数字,就能区分“网络问题还是服务器问题”。大多数争论到这里就会结束。
不要相信平均值
平均响应时间为 200ms 的服务,仍然经常会收到“很慢”的投诉。如果 1,000 个请求中,950 个耗时 50ms,另有 50 个耗时 3 秒,平均值是 197ms。平均值正常,但每 20 人中就有 1 人要等待 3 秒。
因此,应查看百分位数。
| 指标 | 含义 | 用途 |
|---|---|---|
| p50(中位数) | 一半请求比它更快 | 典型体验 |
| p95 | 每 20 人中 1 人经历的值 | 用户开始明显不满的位置 |
| p99 | 每 100 人中 1 人经历的值 | 尾部问题,包括竞争、GC、重试 |
| max | 最差的单次请求 | 追踪异常值 |
如果 p50 不变,只有 p99 上升,问题不是容量,而是竞争。如果从 p50 开始一起上升,则是结构或容量问题。
负载与延迟是不同维度
CPU 使用率 60% 并不代表“还剩 40% 余量”。在排队论中,利用率升高时,等待时间不是线性增长,而是会急剧上升。超过 70% 后,只需再增加少量负载,延迟就可能增长数倍。因此,“CPU 明明还有余量”无法反驳延迟问题。
生产现场中的表现
- “感觉网络很慢” → 测量
ttfb后发现大部分时间都花在服务器处理。 - 只有上午 9 点很慢 → 上班时间并发登录,同时缓存尚未预热。
- 只有特定客户很慢 → 该客户的数据量不同,查询发生全表扫描。
缩小范围后应该测量什么
通过分段已经确认问题在服务器端后,下一步要查看的是服务器内部究竟在等待什么。常见错误是只根据 CPU 使用率判断;正如前一课程所述,服务器的大部分等待时间并不是在等待 CPU 调度。
应按顺序排除四类问题。
**第一,执行等待。**检查已经准备运行的任务是否多于 CPU 核数。如果负载平均值很高而 CPU 使用率很低,原因就不在这里。在容器中还要同时检查前面介绍过的节流。这是平均使用率不高、尾部延迟却突然升高的典型原因。
**第二,输入输出等待。**即等待磁盘或网络。数据库变慢通常也属于这里,此时应修复的不是应用程序,而是查询或索引。
**第三,锁与等待队列。**包括连接池、线程池、应用程序锁和数据库行锁。如果只有并发请求增加时才变慢,几乎总是这类问题;其特点是单独测试时无法复现。
**第四,外部调用。**即我们调用的其他服务变慢。此时我们能修改的只有超时、重试和降级,因此根因与应对措施彼此分离。
区分这四类问题成本最低的方法,是改变负载进行比较。只发送一个请求时也很慢,说明是结构问题(第一类或第二类);只有同时发送多个请求时才变慢,则说明存在竞争(第三类)。仅这一次比较,就能把调查范围缩小一半。
此外,**修复后必须用相同方法重新测量。**相信已经修好,与数字实际发生变化是两回事;如果最初没有测量值,也就没有依据声称问题已经改善。
后续实验要做什么
你将拿到一份包含 340 条真实请求的日志,并亲自回答前面的四个问题。所有答案都在数据中;只要按顺序缩小范围,一句“很慢”就会变成一份能够指向具体版本的报告。