这一章在做什么

这一章是全书的预告:性能工作管哪些事、为什么难,以及后面各章反复要用的几样基本功。最该带走三件事:延迟能直接换算成「最多能快多少」,别的指标大多做不到;观测(计数器、剖析、跟踪)和实验(基准测试)是两只手,生产环境先用观测;遇到问题先把每种资源扫一遍,再往深处钻。读完这一页,你应该知道遇到哪类问题该翻哪一章。

问题落在哪一层,就翻哪一章 应用程序:线程、锁、系统调用 第 5 章 内核:调度、虚拟内存、IO 栈 第 3 章 CPU第 6 章 内存第 7 章 文件系统第 8 章 网络第 10 章 磁盘第 9 章 按什么顺序查:第 2 章 工具的数从哪来:第 4 章 三件工具的说明书 perf 13 · Ftrace 14 · BPF 15 虚拟机和容器:第 11 章 压测和对比:第 12 章 一次完整的排查:第 16 章 左边是一个请求要经过的东西,右边是每一层都用得上的方法、工具和环境。
本站画的全书地图。第 1 章的每一节都指向其中一块;第 6 到 10 章套路相同,遇到哪种资源的问题就直接翻那一章。

什么时候翻这一章

这一章只开头,不展开。按问题找章,可以用这张表(本站整理,不是书里的):

遇到的事翻哪里先看什么
不知道按什么顺序查、怎么判断瓶颈第 2 章USE 方法、延迟分析、统计里的平均值和分布 §2.5.9§2.8
工具输出里的数是从哪来的、开销多大第 4 章计数器、剖析、跟踪三类工具的来源 §4.2§4.3
自己的程序慢:在等锁、等 IO,还是在算第 5 章CPU 剖析和 off-CPU 分析 §5.4.1§5.4.2
CPU 忙、负载高、线程排队第 6 章USE 方法、剖析、火焰图 §6.5§6.7.3
内存一直涨、被 OOM 杀、开始换页第 7 章vmstat 和 PSI §7.5.1§7.5.2
读写文件慢,怀疑缓存第 8 章缓存命中率、文件系统延迟 §8.6.12§8.6.13
磁盘忙、IO 延迟高第 9 章iostat 和延迟分布 §9.6.1§9.6.6
网络延迟、连不上、重传多第 10 章ss、nstat、sar 的网络选项 §10.6.1§10.6.6
容器或虚拟机里数字不对第 11 章多租户和资源限制 §11.1.5
要做压测、对比两个版本第 12 章基准测试常见的错 §12.1.3
想用 perf、Ftrace、BPF 问具体问题第 13–15 章当说明书查

先用中文过一遍

延迟:能直接换算成「最多快多少」

一个成熟的系统里,已知没修的性能问题往往有一堆(§1.5.4)。难的不是找到一个问题,而是挑出影响最大的那个,这就要把每个问题量化。延迟(latency)是等待花掉的时间:一个请求、一次查询、一次文件读,都有自己的延迟。它好用在于能拆、能相减:知道一个请求的时间里有多少花在某件事上,就能算出把这件事完全去掉,最多能快几倍(§1.6)。

拿本站下面「动手」里的小程序说:每个请求约 20 毫秒,其中 6 毫秒在 CPU 上算,14 毫秒在等后端。把计算优化到快一倍,只省 3 毫秒,整体快 1.18 倍;等待减半,快 1.5 倍;等待全部消掉,上限是 20 ÷ 6 ≈ 3.3 倍。别的指标给不出这种结论:IOPS 降了一半,可能是好事,也可能只是每次 IO 变大了。还有两点要记住:延迟要带限定词,「网络延迟」可以指建连接的时间,也可以指整个请求的时间,书里会写成连接延迟、请求延迟;很多地方只给平均延迟或者根本不给,BPF 工具可以在任意位置量,并给出完整分布。

一个请求 20 毫秒,去掉哪一段最划算 现在:20 ms CPU 6 ms 等后端 14 ms 计算快一倍 → 17 ms,只快 1.18 倍 3 ms 等后端 14 ms 等待减半 → 13 ms,快 1.5 倍 CPU 6 ms 等 7 ms 等待全部消掉 → 6 ms,上限 3.3 倍 CPU 6 ms 再往下,只能去减计算了
本站画的示意,数字来自下面「动手」里的程序在 WSL2 上的实测(每个请求平均约 19.8 毫秒,其中约 5.7 毫秒在 CPU 上)。改完再量:计算减半是 17.0 毫秒,等待减半是 13.1 毫秒,和算的一样。

延迟好不好,本身没有标准答案:平均 1 毫秒的磁盘 IO,对一个服务可能很快,对另一个可能太慢(§1.5.1)。把「慢」变成能检查的事,要先定目标,比如平均响应时间不超过多少,或者百分之多少的请求要落在某个延迟以内。

观测和实验:两只手

观测(observability)是靠「看」来理解系统,不改变它的负载。看的手段有三种。计数器(counter)是内核和应用里一直在累加的整数:操作次数、字节数、错误数。工具隔一段时间读两次相减,算出速率、平均值、百分位,这叫统计(statistic);挑出来长期记录、画曲线、设告警的统计叫指标(metric)。计数器便宜、一直开着,但常常只能告诉你「CPU 或磁盘有问题」,说不出为什么(§1.7.1)。剖析(profiling)是定时采样,比如每秒打断几十次、记下正在跑的代码,拼出一张粗略的画像;最常见的是 CPU 剖析,画成火焰图。作者认为在指标之外,CPU 火焰图帮人找到的改进比任何工具都多,而且锁的自旋、过多的 malloc 这类问题也会在火焰图里留下 CPU 的痕迹(§1.7.2)。跟踪(tracing)是把每一个事件都记下来,或者当场汇总,三种里最细(§1.7.3)。

实验(experimentation)是自己施加一个人造的负载,量系统的反应,也就是基准测试。宏基准(macro-benchmark)模拟真实的客户端请求;微基准(micro-benchmark)只测一个部件,比如磁盘或网络,通常更容易重复、也更容易弄懂。实验的长处是负载固定:线上的流量每秒都在变,固定负载把这部分波动去掉,剩下的波动(比如吞吐忽高忽低分成两档)就显出来了。它的代价是会和真实负载抢资源,所以书里的建议是:生产环境先用观测工具,空闲的测试机可以先压测摸清硬件的底(§1.7、§1.8)。只用观测也不对:工具太多,挨个看可能花几个小时,换成一个实验也许更快就有答案。

观测不动负载,实验自己加负载 观测:生产环境先用这只手 计数器 一直在累加的数 回答:哪种资源忙 vmstat、iostat 剖析 定时采样调用栈 回答:时间花在哪 perf、火焰图 跟踪 每个事件都记下 回答:谁、等多久 strace、BCC 实验:另一只手 自己施加人造负载 宏基准:模拟真实请求 微基准:只测一个部件 会和真实负载抢资源 适合空闲的测试机
本站画的示意。从左到右,得到的细节越来越多,代价也越来越高;监控面板上的曲线属于最左边那一格。

跟踪:静态插桩、动态插桩和 BPF

跟踪要先有「插桩点」,事件发生时才有东西可记。静态插桩(static instrumentation)是写在源码里的固定点:内核里叫跟踪点(tracepoint),磁盘 IO、调度、系统调用都有;用户态程序和库里的叫 USDT。像代码里预先埋好的日志语句,位置是写代码的人定的。动态插桩(dynamic instrumentation)是在程序跑起来以后,改内存里的指令插进一段例程,像调试器下断点,只是执行完例程就接着跑,不停下来。对 C/C++ 程序员来说,相当于不重新编译、在线上进程任意一个函数里临时加一行 printf。Linux 内核里的这项能力叫 kprobes,2004 年开始合入(§1.7.3)。

BPF 原本是给 tcpdump 加速过滤表达式的内核小虚拟机,2013 年起扩展成通用的内核执行环境,保证安全,访问数据又快。它让 BCC 和 bpftrace 这两套前端可以「编程」:在任意插桩点上写一小段逻辑,在内核里直接汇总成直方图、计数。书里很多工具(比如抓短命进程的 execsnoop)都是 BCC 工具。这些工具都要 root;BPF 本身在第 3 章讲(§3.4.4),插桩点的原理在第 4 章(§4.3.5–§4.3.8),用法在第 15 章。

头一分钟:先问清楚,再把资源扫一遍

没有方法的排查像钓鱼:随便试,指望碰上(§1.10)。第一步是把「慢」落到实处。工单上写「磁盘慢」,可能只是有人在监控上看见磁盘很忙;应用到底有没有变慢、用什么量的、变慢前动过什么,都要先弄清。书里第一个案例就是先问了几个问题,才发现最初的怀疑很可能只是猜测(§1.11.1;怎样把问题问清楚,见 §2.5.5)。

第二步是在几分钟里把每种资源各看一眼,先排除掉一大片。书里 §1.10.1 给了一张十条命令的检查表,每条都指到详细讲它的那一节,值得在自己的机器上照着跑一遍。本站按要回答的问题换一种排法,顺带补上书外的 PSI:

两点提醒。监控面板上有同样的数,看面板也行,但监控常常一分钟一个点,会把几秒的突发抹平:书里的案例里,监控说磁盘 80%,按秒看却是经常顶到 100%、开始排队。扫完这一遍,你只知道哪种资源可疑,还不知道为什么;接下来按第 2 章的 USE 方法(§2.5.9)把每种资源查完整,再往下钻(§2.5.12),去对应资源那一章用剖析和跟踪找原因。

英文中文一句话
latency延迟等待花掉的时间;能拆、能相减,所以能换算成加速比的上限 §1.6 术语页
observability可观测性、观测靠看来理解系统,不改变负载:计数器、剖析、跟踪 §1.7 术语页
counter / statistic / metric计数器 / 统计 / 指标累加的整数;两次读数算出的速率和平均;挑出来长期监控的那些 §1.7.1 术语页
profiling剖析定时采样,拼出粗略的画像,最常见的是 CPU 剖析 §1.7.2 术语页
flame graph火焰图把采到的调用栈合并画出来,宽度是 CPU 时间的占比 §1.7.2 术语页
tracing跟踪按事件记录,保存下来或当场汇总 §1.7.3 术语页
tracepoint / USDT跟踪点 / 用户态静态跟踪静态插桩:内核和用户态程序源码里预先写好的点 §1.7.3 术语页
dynamic instrumentation动态插桩运行中改内存里的指令插入例程,内核里是 kprobes §1.7.3 术语页
BPFBPF内核里安全的执行环境,BCC 和 bpftrace 靠它编程 §1.7.3 术语页
macro- / micro-benchmark宏基准 / 微基准模拟真实负载 / 只测一个部件;后者更稳定、好重复 §1.8 术语页
workload / resource analysis负载分析 / 资源分析从请求往下看 / 从资源往上看,难题两头都试 §1.4
canary testing金丝雀测试新版本先在一台实例上接一小部分流量 §1.3
non-regression testing非回归测试确认改动没让性能退步;也常被叫作回归测试 §1.11.2
USE methodUSE 方法对每种资源查利用率、饱和度、错误;第 2 章定义 §2.5.9 术语页

动手:在自己的机器上试

把一个请求的时间拆成「在算」和「在等」

下面这个程序假装处理 50 个请求,每个请求先算一会儿,再等一会儿。先猜:把计算优化快一倍,和把等待砍掉一半,哪个收益大、各快多少?然后量。

// req.c:假装处理 50 个请求。每个请求先在 CPU 上算一会儿,再等一会儿(假装在等数据库)
#include <stdio.h>
#include <time.h>
#ifndef WORK
#define WORK 8500000       // 计算量:本站的 WSL2 上大约 6 毫秒
#endif
#ifndef WAIT_MS
#define WAIT_MS 14         // 每个请求等多少毫秒
#endif

static volatile unsigned sink;

static void compute(long n) {                 // 在 CPU 上
    unsigned s = 0;
    for (long i = 0; i < n; i++) s = s * 31 + (unsigned)i;
    sink = s;
}

static void wait_backend(long ms) {           // 不在 CPU 上,只是等
    struct timespec ts = { 0, ms * 1000000L };
    nanosleep(&ts, NULL);
}

int main(void) {
    for (int id = 0; id < 50; id++) {
        compute(WORK);
        wait_backend(WAIT_MS);
    }
    printf("done %u\n", sink);
    return 0;
}
# 先观测:real 是墙上时间,user + sys 是在 CPU 上的时间
$ gcc -O2 req.c -o req
$ time ./req
# 再实验:计算减半、等待减半,各编一份
$ gcc -O2 -DWORK=4250000 req.c -o req_cpu
$ gcc -O2 -DWAIT_MS=7 req.c -o req_wait
$ time ./req_cpu
$ time ./req_wait

本站在 WSL2 上看到的(三次各截了三行):

req:       real 0.988s   user 0.284s   sys 0.000s
req_cpu:   real 0.851s   user 0.146s   sys 0.000s
req_wait:  real 0.655s   user 0.297s   sys 0.004s
  1. 原版跑了约 1 秒,在 CPU 上的只有 0.28 秒,七成多时间在等。这个程序只有一个线程,所以 real 减去 user 和 sys,就是它不在 CPU 上的时间(§6.6.8)。机器很忙时,排队等 CPU 的时间也会算进这一块。
  2. 按延迟估算:去掉等待,上限是 0.99 ÷ 0.28 ≈ 3.5 倍(上面的图按取整的 20 ÷ 6 算,是 3.3 倍);计算减半预计到 0.85 秒,等待减半预计到 0.64 秒左右。实测和估算对得上。先算账,再决定优化哪一段,这就是 §1.6 说的量化。
  3. 前两条命令是观测,后面重新编译再量是实验。真实的服务没法这样随手改参数,但思路一样:先观测出时间花在哪,再用实验确认改了以后真的变快。
WSL2
本站实测过(Debian 13,gcc 14.2,bash 内建的 time),不需要 root。WORK 的值是按本机校准的,换一台机器 6 毫秒会变,比例的道理不变。
服务器
别在生产机上跑。对正在跑的服务没法重编译,可以用 pidstat -u -p PID 1 看它每秒用掉多少 CPU 时间,除以每秒的请求数,得到每个请求在 CPU 上花的时间,再和应用自己记录的请求延迟比。等待花在哪里,用第 5 章的 off-CPU 分析(§5.4.2,BCC 的 offcputime 要 root)。
ARM 板
交叉编译(如 aarch64-linux-gnu-gcc -O2 req.c -o req)后拷上去。板子慢,同样的 WORK 会花更久,按比例调小。shell 内建的 time 或 busybox 的 time 都能给出 real 和 user(看你的 busybox 裁了哪些)。

成书之后

BPF 还是 eBPF:两个名字并用

书里
脚注说 eBPF 是早期对扩展后的 BPF 的叫法,现在这项技术就叫 BPF,全书都写 BPF(§1.7.3)。
今天
两个名字都在用。IETF 在 2024 年 10 月发布了 RFC 9669,定义 BPF 的指令集,摘要里写的是 eBPF,并注明它已经不是任何词的缩写、也常被叫作 BPF;原来的 BPF 有时叫 cBPF(classic BPF)。查资料时两个词都搜一下。
核对于 2026-10。出处:RFC 9669《BPF Instruction Set Architecture (ISA)》(IETF,2024 年 10 月)。

分节地图

这一章是全书的导览,每一节都短,结尾是两个虚构的案例。先读的是讲延迟、观测和实验、头 60 秒清单的几节,它们是后面各章天天要用的基本功;性能为什么难、云计算、两个案例,想了解时再读。

  1. Computer performance is an exciting, varied…约 100 词开篇四条学习目标,也就是这一章的目录。
  2. Systems Performance约 200 词系统性能研究整条数据路径,书里的全栈一直到硬件;手边要有一张数据路径图。
  3. Roles约 200 词角色谁在做性能工作、性能团队怎么分工;上手用不到。
  4. Activities约 500 词活动从立项到上线的十项性能活动;金丝雀测试、蓝绿部署、容量规划在这里出现。
  5. Perspectives约 100 词视角从负载往下看与从资源往上看,第 2 章展开。
  6. Performance Is Challenging约 100 词性能为什么难四个原因的引子。
  7. Subjectivity约 200 词主观性好不好取决于预期;怎样用目标把它变成能检查的事。
  8. Complexity约 300 词复杂性没有明显的起点、连锁故障、瓶颈转移、线上负载在实验室复现不了。
  9. Multiple Causes约 100 词多个原因几件各自正常的事凑在一起才出问题。
  10. Multiple Performance Issues约 200 词多个性能问题问题总有一堆,要量化,挑最要紧的。
  11. Latency约 400 词延迟为什么延迟能估出加速比上限而 IOPS 不能;延迟要带限定词。
  12. Observability约 100 词可观测性观测和实验的分界;生产环境先用哪一种。
  13. Counters, Statistics, and Metrics约 400 词计数器、统计和指标从计数器到告警的几层叫法;指标什么时候够用、什么时候只指方向。
  14. Profiling约 300 词剖析采样画粗略画像;火焰图能从 CPU 的痕迹里看出哪些别的问题。
  15. Tracing约 700 词跟踪静态插桩、动态插桩、BPF 的来历;细节在第 4、15 章。
  16. Experimentation约 400 词实验宏基准和微基准;固定负载能显出什么;为什么两种工具都要用。
  17. Cloud Computing约 200 词云计算按时计费让优化直接省钱;邻居干扰、看不见物理机。
  18. Methodologies约 100 词方法论没有方法的排查是什么样子。
  19. Linux Perf Analysis in 60 Seconds约 100 词Linux 性能分析的头 60 秒一张十条命令的检查表,每条指到详细讲它的节。照着跑一遍。
  20. Case Studies约 100 词案例两个虚构的案例;作者说这只是一种做法。
  21. Slow Disks约 900 词磁盘慢从问清问题、USE 扫资源到和同类机器对比,看方法怎么串起来。
  22. Software Change约 800 词软件变更非回归测试:压测到顶、定速比资源消耗、找出真正的瓶颈。
  23. More Reading约 100 词延伸阅读指向第 16 章和第 2 章,没有新内容。

词与短语

只收先读和用到再查两档的节。斜体那一行是原句里连续的几个词,在电子书里搜它就能找到那一句。

§1.1 Systems Performance

full stack
… we use full stack to mean …
整个软件栈
招聘广告里的「全栈」只指应用那一层(数据库、应用、Web 服务器);这本书里的 full stack 从应用一直往下到内核和硬件。
down to metal
… from the application down to metal …
一直到硬件
metal 指裸机、硬件本身,同 bare metal。

§1.3 Activities

canary testing
… this is known as canary testing …
金丝雀测试
典故是矿工带金丝雀下井,鸟先出事就说明有毒气。新版本先放到一台机器上接一小部分流量,出问题影响也小。
safe-to-fail
… With such safe-to-fail options available …
失败了也不要紧的
出了问题能马上切回去,所以敢直接上生产。
time-to-market
… there may be time-to-market reasons for …
(赶)上市时间

§1.5.1 Subjectivity

see things in black and white
… known for seeing things in black and white …
非黑即白地看问题
不是「看黑白画面」。软件 bug 要么有要么没有,性能却没有这么分明。
to begin with
… there is an issue to begin with …
(到底有没有问题)本身
不是「首先」。意思是连「是不是真有问题」都不清楚。

§1.5.2 Complexity

line of work
… intellectually challenging line of work.
行当,职业
不是「一行工作」。

§1.5.4 Multiple Performance Issues

You might be surprised!
… You might be surprised! …
你会吓一跳的
往轻里说:去 bug 库里搜 performance,会看到一大堆已知没修的性能问题。

§1.6 Latency

screen paint
… from link click to screen paint.
页面画到屏幕上
paint 是浏览器把页面绘制出来,不是「涂漆」。
take their business elsewhere
… customers may take their business elsewhere.
转去别家
business 在这里是「生意、光顾」,客户流失的委婉说法。
up to
… run up to 5x more slowly.
最多(可达)
给的是上限,不是确定的倍数。
qualifying terms
… be ambiguous without qualifying terms.
限定词
qualify 在这里是「加限定、加修饰」,不是「合格」。

§1.7 Observability

perturb
… may perturb production workloads through resource contention.
干扰
压测和线上负载抢资源,把要观测的对象本身改变了。

§1.7.1 Counters, Statistics, and Metrics

not rigid
… use in the industry is not rigid.
(用法)不严格
计数器、统计、指标三个词在业内常常混着用。

§1.7.2 Profiling

paint a coarse picture
… paint a coarse picture of the target.
勾勒出粗略的轮廓
paint 是比喻:采样只拿一部分数据,画像是粗的,不是精确记录。
performance win
… find more performance wins than any …
一次性能改进(带来的收益)
Gregg 常用的说法,win 是「找到的一处收益」,不是「赢」。
footprints they leave behind
… by the CPU footprints they leave behind.
留下的痕迹
锁、内存这类问题本身不是 CPU 问题,但会在 CPU 上留下印子,比如自旋、频繁分配。

§1.7.3 Tracing

on-the-fly
… or consumed on-the-fly for custom summaries …
当场(处理)
不存下来,边采边汇总。不是「在飞行中」。
venture into
… like venturing into a dark room …
摸进(一个陌生的地方)
venture 带「冒险」的意味。
production-safe
… easy to use and production-safe.
能放心在生产环境用的

§1.8 Experimentation

lap time
… a car’s lap time at Laguna …
单圈时间
赛车绕赛道一圈的成绩,比作宏基准;极速和零到 60 英里/小时的加速时间比作微基准。
bi-modal
… result that shows bi-modal throughput.
双峰的
数值集中在两档,平均值落在两档中间,哪一档也代表不了。

§1.9 Cloud Computing

at short notice
… from the cloud at short notice.
临时、随时
notice 是「通知、预告」:提前很短时间打个招呼就能加。
locked into
… you may be locked into a fixed …
被(合同)套住
不是「锁在里面」,是签了长期合同、想省钱也退不掉。

§1.10 Methodologies

fishing expedition
… can turn into a fishing expedition …
撒网碰运气
本义是钓鱼之旅,引申为没有目标地四处搜寻、指望碰上点什么。
catch a win
… in the hope of catching a win.
碰上一个改进
接着上面的钓鱼比喻:catch 是「钓到」。

§1.11 Case Studies

for your critical consideration
… for your critical consideration.
供你审慎地参考
critical 是「批判性的、挑剔的」,不是「关键的」。作者提醒案例里的做法不必照搬。

§1.11.1 Slow Disks

file a ticket
… has filed a support ticket complaining …
提工单
see for oneself
… to AcmeMon to see for himself.
亲眼看一看
不轻信别人转述的结论,自己去看数据。
creep downward
… watches disk utilization creep downward in …
一点点往下降
creep 是「慢慢爬」,强调变化缓慢,不是「令人毛骨悚然」。

§1.11.2 Software Change

level off
… throughput levels off at around 700 …
不再上升,持平
曲线变平了。压测里看到它,说明某处到顶了。
abrupt ceiling
… Both appear to reach an abrupt ceiling.
突然撞到的上限
吞吐曲线不是慢慢弯下来,而是一下子变平。

诊断题:换成你来查

场景和输出都是本站编的。先自己判断,再点选项看解释。

把 JSON 解析快一倍,整体能快多少?§1.6

场景:你的 C++ 服务平均每个请求 40 毫秒。用跟踪工具拆开一个请求,时间是这样分的:

parse_json    8 ms   (on-CPU)
mysql_query  30 ms   (waiting)
other         2 ms

同事打算花两周把 JSON 解析器重写,快一倍。

解析从 8 毫秒降到 4 毫秒,请求从 40 变成 36,40 ÷ 36 ≈ 1.11 倍。同样的账算一下数据库那一段:等待全部消掉,上限是 40 ÷ 10 = 4 倍,哪怕只砍掉一半(加缓存、补索引)也是 40 ÷ 25 = 1.6 倍。按延迟算,先动数据库那一段更划算。这类估算不需要压测,有延迟的拆分就能算。

IOPS 降了八倍,这次改动是好是坏?§1.6

场景:一块 ARM 板上的日志服务写 eMMC。你把写日志的方式从「每条立刻写」改成「攒一批再写」。改动前后各跑一分钟 iostat:

        w/s
before  1200
after    150

攒批以后每次写得更大,次数少了不等于干的活少了,书里正是拿这一点说明 IOPS 不能直接比较。该看的是 iostat 里每次写的平均大小(wareq-sz)和平均等待(w_await),更该看的是应用这边:记一条日志的延迟是不是降了。eMMC 故障要看 dmesg 里的 IO 错误,不能从次数推断。

线上网关的 p99 在涨,同事提议怎么查,哪个对?§1.8

场景:生产环境里一台网关的 p99 延迟这周涨了一倍。同事说:「在这台机器上跑十分钟 fio 和压测工具,看看盘和网卡到底能跑多快,就知道是不是硬件不行了。」

压测会和线上请求抢盘、抢网卡,把正在出问题的系统搅得更乱,所以生产环境先用观测工具。实验并不是没用:在一台空闲的同配置机器上压,能知道硬件的底,也能用固定负载复现问题,这是另一只手。重启可能让现象暂时消失,也把排查的线索一起抹掉了。

监控说磁盘 55%,iostat 却是这样,怎么理解?§1.11.1

场景:数据库的慢查询变多了。监控系统每分钟一个点,磁盘利用率一直在 55% 左右。你登上机器跑 iostat -x 1,连着看了几秒:

%util   aqu-sz   r_await
 100     9.8      41.2
  12     0.1       0.6
 100    11.3      47.9
  10     0.1       0.5

满载的那几秒里队列有十来个请求,单次读的等待从不到 1 毫秒涨到四十多毫秒,查询变慢就落在这些时刻。一分钟的平均值把 100% 和 10% 平均成了中间值,两档都代表不了。下一步按负载特征看是谁在突发地读(第 9 章的 iostat 和 biolatency,§9.6.1、§9.6.6),再想办法让它摊平或者走缓存。

压测压不上去,瓶颈在哪?§1.11.2

场景:你给自己的 C++ 服务做发版前的压测,压测工具是组里以前写的单线程程序。逐步加目标速率:

target   achieved   server_cpu
10000      10000        16%
15000      15000        24%
20000      18100        29%
30000      18200        29%

服务端 CPU、磁盘、网卡都不忙,线程也不排队。

服务端资源都闲着、吞吐却平了,说明限制在别处。数据路径上还有客户端和网络,单线程的压测工具最容易先到顶:在客户端机器上 pidstat -t -p PID 1 看它的线程是不是 100%。解决办法是多开几个客户端、放到不同机器上一起压。至于新旧版本有没有退步,先固定一个两边都压得住的速率,比较每个请求用掉多少 CPU。

值得停下来的句子

the real task isn’t finding an issue; it’s identifying which issue or issues matter the most.— §1.5.4。本站译:真正的活不是找到一个问题,而是认出哪一个或哪几个问题最要紧。

排查时最容易犯的错,是看到第一个「不正常」的数就认定是它。成熟的软件里本来就躺着一堆已知的性能问题,找到一个毫不稀奇。这句话把排查从「找问题」改成「排优先级」,而排优先级就要量化:这个问题让请求慢了多少毫秒、修好它最多快几倍。这也是为什么书里紧接着就讲延迟。

you have two hands, observability and experimentation. Only using one type of tool is like trying to solve a problem one-handed.— §1.8。本站译:你有两只手,观测和实验。只用一种工具,就像单手解决问题。

这是作者转述一位前辈工程师的比喻。只会看监控的人,可能在几十个工具之间转几个小时;只会压测的人,在生产机上会把现场搅乱。实际的节奏是交替的:观测给出假设,实验验证假设,再回到观测确认改动的效果。上面「动手」里的小程序就是这个节奏的缩小版。

带走的几条

一句话:先量化再动手:用延迟算出上限,生产上先观测,扫完资源再往深处钻。

先算上限,再决定优化什么

量出一段占请求多少时间,去掉它最多快「总时间 ÷ 剩余时间」倍。只占两成的部分优化到零,也只快 1.25 倍。

§1.6
只看 IOPS 说不出好坏

次数少了,可能只是每次变大了。要配上每次的大小和延迟一起看。

§1.6
生产环境先观测

压测会和线上负载抢资源。实验放到空闲的同配置机器上做,但别只用一只手。

§1.8
先问清楚,再扫一遍资源

问清慢是怎么量的、从什么时候开始、改过什么;再把 CPU、内存、磁盘、网络、错误各看一眼。书里 §1.10.1 有现成的检查表。

§1.10.1
监控的间隔会抹平突发

一分钟一个点的 55%,可能是一半时间满载。到现场用 1 秒的间隔看。

§1.11.1
压不上去时,先查压测端

服务端都闲着、吞吐却平了,瓶颈可能在压测客户端、网络,或者负载生成器自己。

§1.11.2