这一章在做什么
这一章不讲具体工具,讲排查的思路和读数的常识。思路是一组方法:先把问题说清楚,用 RED 看服务、用 USE 扫一遍资源,分清是负载太大还是实现有毛病,再沿着延迟一层层往下拆,每一步都用假设和测试来验证。常识是几个最容易读错的数:利用率和饱和度不是一回事;排队让延迟在利用率远没到 100% 时就变陡;平均值会把分布藏起来。后面各章的「方法」一节,都是这里在某种资源上的具体化。
什么时候翻这一章
- 接到「服务变慢了」,不知道从哪下手问题陈述、RED、USE 三件事,几分钟就能开个好头,不用先挑工具。下面「方法」一节把它们排成了顺序。§2.5.5§2.5.9§2.5.10
- 利用率才六七成,延迟却翻了一倍排队论说明了为什么不用等到 100%,以及为什么磁盘这类不能插队的资源更早出事。§2.6.5§2.3.11场景手册 →
- 平均延迟好看,p99 很难看平均值掩盖分布;分布有两个峰时,平均值落在谷里,谁也不代表。§2.8.2§2.8.5场景手册 →
- 升级或改了参数,说不清变好还是变坏科学方法:先写下预测,一次只改一处,用同一个指标比前后;收益用时间来算。§2.5.6§2.8.1场景手册 →
- 要估还能扛多少流量、该不该加机器按每个请求消耗的资源外推上限,再用扩展性模型看加并发会不会适得其反。§2.7.1§2.6.3§2.6.4场景手册 →
这一章是全书的总纲:第 5–10 章各有一节 Methodology,在应用、CPU、内存、文件系统、磁盘、网络上重讲 USE、负载特征、静态调优;第 12 章接着讲基准测试。遇到具体资源的问题,先在这里定好思路,再去对应的章找工具。
先用中文过一遍
延迟、利用率、饱和度:最常用也最常读错的三个数
响应时间(response time)是一个操作从发出到完成的全部时间,等于排队等待加上真正被处理的服务时间(service time)。延迟(latency)这个词有两种用法:严格说是「等着被处理」的那一段,日常又常指整个响应时间(§2.1、§2.3.1)。所以说延迟时要带上量的是哪一段:DNS 解析、TCP 建连、请求处理。延迟好用,是因为它的单位是时间,可以相加、可以比较:「每秒 100 次网络 IO」和「每秒 50 次磁盘 IO」比不出谁更伤,换成「每秒在网络上等了 100 ms、在磁盘上等了 50 ms」就一目了然。
利用率(utilization)在这本书里多数时候指按时间算的:一段时间里,这个资源有多少时间在忙(§2.3.11)。它有两个坑。第一,能同时处理多个请求的东西(SSD、存储阵列、八个工作线程的线程池),「100% 的时间都在忙」不等于「再也接不下活」,后者是按容量算的利用率。内存这类按容量计的资源用的就是后一种定义。第二,利用率永远是某个时间段的平均:一分钟平均 40%,可能藏着几秒钟的 100%。
饱和度(saturation)问的是:有多少活已经来了,却因为资源被占着只能排队(§2.3.12)。排队就意味着有人在等,所以书里的态度是任何程度的饱和都值得看。按时间算的利用率没到 100% 时也可能已经有排队,下面「排队」那一节会算给你看。
USE 和 RED:一个站在机器里,一个站在服务门口
USE 方法一句话就能说完:对每一个资源,查利用率(Utilization)、饱和度(Saturation)、错误(Errors)(§2.5.9)。它的力量在「每一个」:先列资源,再为每个资源找指标,而不是先打开手头的工具看它显示什么。这样一来,找不到工具回答的问题也会留在清单上,成为「已知的未知」(§2.3.15),而不会因为没有工具就被忘掉。查的顺序是先错误(客观,最快排除)、再饱和(不为零就值得看)、最后利用率。三项都正常也有用:可以比较放心地说「不是这个资源」,把范围缩小。
「资源」不只是 CPU、内存、磁盘、网卡。书里把软件资源也算进来:一把互斥锁,持有的时间是利用率,排队等它的线程是饱和度;一个线程池,工人忙的时间是利用率,排着等工人的请求是饱和度;进程数、文件描述符的上限用光了,报错就是错误。容器里的 cgroup 限额也一样能套上去。
RED 方法是 Tom Wilkie 为微服务提出的:对每一个服务,查请求率(Rate)、错误(Errors)、耗时(Duration),耗时要看分布而不只看平均(§2.5.10)。书里说两者互补:USE 看机器的健康,RED 看用户感受到的健康。RED 里的请求率还是一条早期线索:请求率没变而耗时涨了,问题多半在服务自身;两个一起涨,先怀疑负载(§2.3.8)。
排队:为什么不用等到 100%
把一个处理线程、一块磁盘、一把锁都看成一个服务台:请求按平均速率 λ 到达,每个请求要占用它 S 的时间。利用率就是 ρ = λ × S:每秒来 600 个、每个 1 ms,ρ 是 0.6。排队论(queueing theory)回答的是:ρ 涨上去,平均要等多久(§2.6.5)。
答案取决于到达和服务时间有多随机。书里用 Kendall 记法写成「到达/服务/服务台数」:M 表示随机(指数分布),D 表示固定。两个最常用的单服务台模型:
- M/M/1,到达和服务时间都随机:平均响应时间 = S / (1 − ρ)。
- M/D/1,到达随机、服务时间固定:平均等待 = ρS / (2(1 − ρ)),平均响应时间 = S + 平均等待,也就是书里写的 S(2 − ρ) / (2(1 − ρ))。
代几个数(S = 1 ms):M/D/1 在 60% 是 1.75 ms,约 67% 正好翻倍到 2 ms,80% 是 3 ms;M/M/1 在 60% 已经是 2.5 ms,80% 是 5 ms。书里的说法是过了六成平均响应时间就到两倍上下、八成到三倍,所以磁盘这类请求通常一旦开始就不能被打断、只能排队等的资源,远没到 100% 就会成为问题;CPU 不同,高优先级的工作可以抢占。书里还提醒:M/D/1 在某种意义上是最好的情况,服务时间一有波动,平均值就更高;p90、p99 过了六成以后恶化得比平均值快得多。
另一个随手能用的工具是 Little 定律(Little’s law):系统里平均的请求数 L = 到达率 λ × 每个请求在系统里的平均时间 W。每秒 800 个请求、平均 5 ms,系统里平均就有 4 个请求在处理或排队。拿它可以从监控里的两个数推出第三个,或者核对线程池、连接池该开多大。
平均值、百分位和多峰分布
平均值把一组数压成一个数,最常用的是算术平均。另外两种各有用处(§2.8.2):几何平均适合把几层各自的提速倍数合起来;调和平均适合求速率的平均。比如下载 1000 MB,前 200 MB 是 100 MB/s,后 800 MB 被限到 20 MB/s,总共用 2 + 40 = 42 秒,平均是 1000 / 42 ≈ 24 MB/s,而不是 (100 + 20) / 2 = 60。负载平均那种衰减平均(decayed average)给近期更大的权重,细节在 §6.6.1。
描述分布要用别的数(§2.8.3、§2.8.4):标准差说明离散程度,单看说明不了多少,除以平均值得到变异系数才好比较;百分位说明「最慢的那一小撮」有多慢,p50 就是中位数,p99 是 99% 的请求都比它快的那个值,SLA 里也可能写 p99 或 p99.9。
可这些数默认分布只有一个峰。系统里的延迟却经常是两个峰:缓存命中很快、未命中很慢;走快路径很快、走慢路径很慢(§2.8.5)。这时平均值落在两个峰之间,那里可能一个请求都没有。还有极少数特别慢的离群值(outlier),除了最大值几乎什么指标都看不出它们(§2.8.6)。办法是直接看完整的分布:直方图、热图(§2.10.3)。
| 英文 | 中文 | 一句话 |
|---|---|---|
| response time | 响应时间 | 排队等待加服务时间,操作从发出到完成的全部时间 §2.1 术语页 |
| latency | 延迟 | 严格说是等待的那段,也常指整个响应时间;说清量的是哪一段 §2.3.1 术语页 |
| service time | 服务时间 | 请求真正被处理的时间,不含排队 §2.1 |
| utilization | 利用率 | 一段时间里资源忙的比例;能并行的设备忙满不等于满载 §2.3.11 术语页 |
| saturation | 饱和度 | 来了却只能排队的工作,书里也叫 pressure §2.3.12 术语页 |
| bottleneck | 瓶颈 | 限制整个系统性能的那个资源 §2.1 |
| USE method | USE 方法 | 对每个资源查利用率、饱和度、错误 §2.5.9 术语页 |
| RED method | RED 方法 | 对每个服务查请求率、错误、耗时 §2.5.10 术语页 |
| workload characterization | 负载特征分析 | 只看输入,描述施加在系统上的负载,而不是它表现得怎样 §2.5.11 术语页 |
| drill-down analysis | 下钻分析 | 从高处看起,丢掉无关的部分,往有意思的地方一层层挖 §2.5.12 |
| knee point | 拐点 | 扩展曲线从线性变成受竞争限制的那个点 §2.3.9 |
| Little’s law | Little 定律 | 系统里的平均请求数 = 到达率 × 平均停留时间 §2.6.5 术语页 |
| M/M/1, M/D/1 | 排队模型 | Kendall 记法:到达/服务/服务台数,M 随机、D 固定 §2.6.5 |
| percentile | 百分位 | p99 是 99% 的值都不超过它的那个数,量最慢的那一小撮 §2.8.3 术语页 |
| multimodal distribution | 多峰分布 | 有两个以上的峰,平均值和标准差都会误导 §2.8.5 术语页 |
方法:按什么顺序查
书里只定了两条顺序:碰到新问题,第一个用问题陈述(§2.5);USE 方法要在排查早期用,先把系统性的瓶颈找出来(§2.5.9)。其余方法按情况取用。本站把它们排成一次排查的七步,前三步不需要任何特殊工具,十几分钟就能做完;第 4、5 步才开始用到后面各章的剖析和跟踪工具。
- 问题到底是什么?
先别急着登录机器。把「慢」翻译成一个能量的数:哪类请求、看平均还是 p99、从多少变成了多少;再问它以前快过没有、最近变过什么(代码、配置、内核、流量、机器)。书里把这一步放在所有方法之前,作者说过有时只靠问话就在电话里把问题解决了。§2.5.5
- 负载变了,还是服务变了?
拉出这个服务的请求率、错误数和耗时分布(RED)。请求率平稳而耗时上升,问题多半在服务自身:实现、配置、依赖、它用的资源;请求率和耗时一起涨,先当负载问题,转第 4 步看压力从哪来。C++ 服务可以从接入日志或已有的指标里取每秒请求数和 p50、p99。§2.5.10§2.3.8
- 哪个资源扛不住了?
USE:列出资源(CPU、内存、网卡、磁盘,加上线程池、锁、文件描述符这些软件资源,容器里还有 cgroup 限额),每个依次查错误、饱和度、利用率。书里说最常见的问题往往出在最好查的几项上:CPU 饱和、内存不够、网卡跑满、磁盘忙。起步的命令可以照 §1.10.1 的「60 秒」清单,Linux 上逐项的指标在附录 A。查不到的指标记下来。§2.5.9§1.10.1
- 压力从哪来、长什么样?
负载特征:谁在压(进程、用户、客户端 IP),为什么(调用栈),压的是什么样(读写比、大小、频率,连同它的波动),随时间怎么变(有没有日周期)。答案再显然也查一遍,书里的例子是本以为只有自家 Web 服务器在连数据库,一查是整个互联网在打。最大的收益来自去掉不该有的工作:死循环的线程、重试风暴、高峰时段的备份;去不掉就限流、挪到低峰。§2.5.11§2.5.20
- 时间花在哪一段?
下钻和延迟分析:拿一个慢请求,把时间一分为二,追大的那一半,再分。典型的几刀是:在 CPU 上还是不在(第 5、6 章的 CPU 剖析和 off-CPU 分析),不在时是等锁还是等 IO,IO 时间是在排队还是在被服务。拆到能动手为止;逼自己多问几次「为什么」。汇总值把细节抹掉时,用事件跟踪一个一个地看。§2.5.12§2.5.13§5.4.2§2.5.15
- 猜得对吗?
每个怀疑都写成「假设 + 预测」再去验证:观测(量一量,预测的数对不对)或实验(改一处,预测会变好还是变坏)。实验一次只改一个因素,没效果就先改回去再试下一个;故意让它变差也是一种验证。从假设到数据的来回越快,错的猜测死得越早。§2.5.6§2.5.7
- 修好能快多少?什么时候停?
用时间估收益:请求 12 ms,可优化的那段占 3 ms,就算降到零也只快 1.3 倍。修完用同一个指标比前后,看分布而不只看平均。已经解释了大部分的变慢,或者再挖下去的成本超过收益,就停。什么都没找到时,不加负载把配置静态地过一遍:版本、协商速率、调试开关、快满的文件系统。§2.8.1§2.3.6§2.5.17
反过来,有三种做法书里叫「反方法」,排查时发现自己在这么做就该停一下:只跑自己熟悉的工具,因为那里「亮」(路灯效应);随手改参数看看会不会好;没有数据就把问题推给网络组、存储组。第一种即使找到了问题,也可能是「一个」问题而不是「那个」问题;第二种既慢,又会留下没人说得清的配置。
动手:模拟器
先猜:一个每次固定花 1 ms 的处理线程,利用率从 30% 升到 60%,平均响应时间涨多少?升到 90% 呢?再把服务时间换成随机的(有的请求快、有的慢,平均还是 1 ms),同样 60% 的利用率,等待会变成几倍?拖动滑杆或点下面的按钮验证。
利用率与排队延迟
一个服务台,平均服务时间 S = 1 ms。拖利用率,看平均等待、平均响应和队列长度怎么变;切换「到达和服务都随机」(M/M/1)和「服务时间固定」(M/D/1)。上面的曲线按公式算,下面是用带种子的随机数实际模拟 1.8 万个请求的结果。
按公式,此刻平均在排队的请求(每格一个,不含正在处理的那个)
模拟:连续 150 个请求各自的响应时间(橙色是超过平均 3 倍的)
- 选「服务时间固定」,点 60% 和 80%:平均响应是 1.75 ms 和 3 ms。翻倍的点在哪?把滑杆慢慢往右拖,看 2 × 服务时间那条虚线在约 67% 处被穿过。§2.6.5
- 停在同一个利用率,来回切换两种模型:排队等待正好差一倍。服务时间本身的波动也在制造排队。想想你的服务:请求处理时间越不均匀(有的 0.1 ms、有的 20 ms),同样的 CPU 利用率下排得越久。
- 拖到 90%,选「到达和服务都随机」,点几次「换一批随机数」:模拟的平均值和公式差多少?下面那排柱子里最高的是平均的几倍?高利用率时队列一旦排起来要很久才消掉,短时间量出来的数本来就不稳,p99 更是如此。§2.8.3
分节地图
这一章分三块:背景(§2.1–2.4)、方法(§2.5–2.7)、指标(§2.8–2.10)。先读的是:延迟、利用率、饱和度的定义,负载还是架构,问题陈述和科学方法,USE、RED、负载特征、下钻和延迟分析,排队论,以及平均值、百分位、多峰分布。这些是后面每一章都默认你知道的。扩展性模型、容量规划、可视化几节,做压测和画图时再回来查。
- Give a man a fish and you…约 400 词开篇作者为什么写方法论:只会读指标不够;这一章的三个部分。
- Terminology约 300 词术语IOPS、吞吐、响应时间、延迟等定义;延迟有两种用法。
- Models约 100 词模型两个简单模型的引子。
- System Under Test约 200 词被测系统干扰从哪来;云上看不到同一台宿主上的邻居。
- Queueing System约 100 词排队系统把组件看成排队系统来预测,细节在排队论一节。
- Concepts约 100 词概念一组概念的引子。
- Latency约 400 词延迟延迟量的是哪一段;为什么尽量换算成时间来比较。
- Time Scales约 200 词时间尺度从 CPU 周期到整机重启,各种延迟差几个数量级。
- Trade-Offs约 200 词权衡好、快、省只能选两样;CPU 换内存;参数的两头。
- Tuning Efforts约 300 词在哪一层调越靠近干活的地方调,收益越大。
- Level of Appropriateness约 300 词做到什么程度做多深看投入产出;高频交易和小创业公司的差别。
- When to Stop Analysis约 400 词什么时候停三种可以停下来的情况。
- Point-in-Time Recommendations约 300 词建议有时效网上搜来的参数为什么危险;参数改动最好进版本控制。
- Load vs. Architecture约 200 词负载还是架构排队是因为压力太大,还是因为实现本身有问题。
- Scalability约 400 词扩展性吞吐随负载的曲线和拐点;返回错误为什么能保住延迟。
- Metrics约 300 词指标常见指标类型;观测有开销,指标本身也会错。
- Utilization约 500 词利用率按时间和按容量两种定义;忙满不等于装满。
- Saturation约 100 词饱和度排不上的工作就是饱和,任何程度都值得看。
- Profiling约 100 词剖析定时采样得到粗粒度的画面,细节在第 6 章。
- Caching约 800 词缓存命中率和未命中率哪个更说明问题;冷、温、热缓存。
- Known-Unknowns约 200 词已知的未知知道自己不知道什么,才知道去查什么。
- Perspectives约 100 词视角两种分析视角的引子。
- Resource Analysis约 200 词资源分析从资源往上看,盯利用率和饱和度。
- Workload Analysis约 300 词负载分析从应用往下看,盯请求、延迟和错误。
- Methodology约 200 词方法方法总表;处理新问题时第一个该用的是问题陈述。
- Streetlight Anti-Method约 200 词路灯反方法只用熟悉的工具,找到的未必是那个问题。
- Random Change Anti-Method约 200 词随机改动反方法乱改参数看效果:慢,还留下没人懂的配置。
- Blame-Someone-Else Anti-Method约 100 词甩锅反方法没有数据就把问题推给别的团队;怎么应对。
- Ad Hoc Checklist Method约 300 词临时检查清单现成清单见效快,但偏向有现成修法的问题,要常更新。
- Problem Statement约 200 词问题陈述碰到新问题时先问的几件事。
- Scientific Method约 500 词科学方法问题、假设、预测、测试、分析;观测和实验两种测试。
- Diagnosis Cycle约 100 词诊断循环假设和数据之间来回要快。
- Tools Method约 200 词工具法按工具挨个查,盲区自己看不见。
- The USE Method约 1800 词USE 方法对每个资源查利用率、饱和度、错误:顺序、资源清单、读法、软件资源。
- The RED Method约 300 词RED 方法对每个服务查请求率、错误、耗时;请求率是负载还是架构的线索。
- Workload Characterization约 500 词负载特征用几个问题描述施加的负载;最大的收益来自去掉不必要的工作。
- Drill-Down Analysis约 600 词下钻分析监控、定位、分析三段;五个为什么。
- Latency Analysis约 300 词延迟分析把延迟一分为二,追大的那一半。
- Method R约 100 词方法 ROracle 数据库的方法,思路就是延迟分析,知道名字即可。
- Event Tracing约 300 词事件跟踪汇总丢了细节时逐个看事件:输入、时间、结果。
- Baseline Statistics约 400 词基线统计平时存一份全量指标,出问题时有得比。
- Static Performance Tuning约 200 词静态性能调优不加负载,逐个组件查配置合不合理。
- Cache Tuning约 200 词缓存调优缓存放得越高越好;查命中率、大小和双重缓存。
- Micro-Benchmarking约 300 词微基准测试简单的人造负载;最好再用别的工具核对一遍。
- Performance Mantras约 200 词性能箴言七句话,按效果从大到小排的优化方向。
- Modeling约 200 词建模建模、模拟、测量三种评估,最好做两种。
- Enterprise vs. Cloud约 100 词企业与云一段观点:云上可以租环境直接测,不必建模。
- Visual Identification约 400 词目测从测试曲线认出线性、竞争、一致性、拐点和天花板。
- Amdahl’s Law of Scalability约 300 词Amdahl 扩展性定律串行部分限制扩展;怎么用测试数据拟合参数。
- Universal Scalability Law约 200 词通用扩展性定律多一个一致性系数,能描述加并发反而变慢。
- Queueing Theory约 800 词排队论Little 定律、Kendall 记法;M/D/1 为什么过了六成就疼。
- Capacity Planning约 100 词容量规划容量规划的引子。
- Resource Limits约 500 词资源上限按每个请求的资源消耗外推最大吞吐。
- Factor Analysis约 400 词因素分析配置组合太多时,从最大配置一项项往下减。
- Scaling Solutions约 300 词扩展方案纵向、横向扩展,自动伸缩和分片。
- Statistics约 100 词统计统计一节的引子。
- Quantifying Performance Gains约 200 词量化收益用观测或实验估计修好能快多少。
- Averages约 400 词平均值几种平均值;按时间的平均和衰减平均会掩盖突发。
- Standard Deviation, Percentiles, Median约 100 词标准差、百分位、中位数描述分布的几个数,SLA 为什么写百分位。
- Coefficient of Variation约 100 词变异系数标准差除以平均值,变成一个能比较的数。
- Multimodal Distributions约 200 词多峰分布双峰时平均值落在谷里,谁也不代表。
- Outliers约 200 词离群值极少数极慢的请求,多数指标都看不出来。
- Monitoring约 100 词监控把指标记成时间序列,和过去比。
- Time-Based Patterns约 300 词时间规律按小时、天、周、季度、年的周期,和不规律的起落。
- Monitoring Products约 200 词监控产品监控产品的一般介绍,选型时看第 4 章更合适。
- Summary-Since-Boot约 100 词开机以来的汇总没有监控时,至少和开机以来的平均值比一比。
- Visualizations约 100 词可视化可视化的引子。
- Line Chart约 200 词折线图只画平均值的折线和加上百分位的折线差在哪。
- Scatter Plots约 200 词散点图每个事件一个点,看得见离群值;点多了糊成一片。
- Heat Maps约 300 词热图把散点按桶量化,量再大也看得清分布和双峰。
- Timeline Charts约 200 词时间线图浏览器的瀑布图;服务端看线程和 CPU 的时间线。
- Surface Plot约 200 词曲面图三维线框图,要成规模机房的数据,单机排查用不到。
- Visualization Tools约 100 词可视化工具文本工具和图形工具的泛泛比较,没有可操作的内容。
- Exercises约 100 词习题习题;本页的诊断题可以代替。
词与短语
只收先读和用到再查两档的节。斜体那一行是原句里连续的几个词,在电子书里搜它就能找到那一句。
§0 开篇
§2.3.4 Tuning Efforts
§2.3.5 Level of Appropriateness
§2.3.6 When to Stop Analysis
§2.3.7 Point-in-Time Recommendations
§2.3.8 Load vs. Architecture
§2.3.10 Metrics
§2.5.1 Streetlight Anti-Method
§2.5.2 Random Change Anti-Method
§2.5.3 Blame-Someone-Else Anti-Method
§2.5.4 Ad Hoc Checklist Method
§2.5.6 Scientific Method
§2.5.8 Tools Method
§2.5.9 The USE Method
§2.5.11 Workload Characterization
§2.5.12 Drill-Down Analysis
§2.5.13 Latency Analysis
§2.5.16 Baseline Statistics
§2.5.20 Performance Mantras
§2.6.5 Queueing Theory
§2.7.2 Factor Analysis
§2.8.2 Averages
§2.8.5 Multimodal Distributions
§2.10.2 Scatter Plots
诊断题:换成你来查
场景和输出都是本站编的。先自己判断,再点选项看解释。
场景:你的 C++ 推送网关,周二下午开始有用户抱怨慢。你从接入层的指标里拉了三个时段:
time req/s err/s p50 p99 Mon 15h 4200 2 3ms 18ms Tue 15h 4150 3 4ms 95ms Tue 16h 4180 2 4ms 110ms
RED 里的请求率是「负载还是架构」的第一条线索:请求率持平、耗时上升,指向服务自身(代码、配置、依赖、它用的资源),加机器解决的是负载问题。p50 只涨了一点、p99 涨了五六倍,说明一部分请求走上了慢路径:用问题陈述问「最近改了什么」,同时把慢请求的时间拆开。错误数正常只说明没失败,不说明不慢;没有数据就推给网络组,就是书里的甩锅反方法。
场景:ARM 板上一个单线程的日志压缩线程,每条日志固定耗时约 2 ms,现在每秒来 300 条,利用率 60%,每条从进队列到写完平均 3.5 ms。下个版本日志量要涨到每秒 400 条。按 M/D/1 估,每条平均要多久?
M/D/1 的平均响应是 S(2 − ρ) / (2(1 − ρ)):ρ = 0.6 时 2 × 1.4 / 0.8 = 3.5 ms,ρ = 0.8 时 2 × 1.2 / 0.4 = 6 ms。流量涨 33%,延迟涨 71%,这就是排队带来的非线性。80% 没到 100%,队列是稳定的,只是等得更久;超过 100% 才会无限增长。而且固定服务时间是最好的情况:每条耗时有波动的话(实际总有),按 M/M/1 是 5 ms 涨到 10 ms。下一步要么把单条压缩变快(降低 S),要么拆成两个线程。
场景:一个带本地 LRU 缓存的配置查询服务,监控显示平均延迟 3.2 ms,SLA 写的是平均不超过 5 ms,一切「正常」。你把一分钟的请求按延迟分了桶:
latency count 0-1ms 6400 1-4ms 150 4-8ms 1900 8-16ms 1500
平均值、标准差、百分位都默认分布只有一个峰。这里的平均值没有算错,只是落在两个峰之间,几乎没有请求真的花了 3.2 ms;中位数也只说出了快的那一峰。下一步看缓存的命中率和每秒未命中次数(§2.3.14),再对未命中那条路径做延迟分析。SLA 最好改用 p99 这类百分位,再配上直方图。
场景:8 核服务器上的 C++ 撮合服务,监控是 5 分钟粒度,CPU 从没超过 50%,但每隔几分钟就有一批请求超时。你在超时前后跑了 vmstat 1:
r us sy id 3 38 4 58 19 93 6 1 22 94 5 1 2 35 4 61
利用率总是某个时间段的平均,5 分钟的 50% 里可以藏着好几秒的 100%。vmstat 的 r 是可运行的线程数(在跑的加在等的,§6.6.2),19、22 远大于 8 核,就是 CPU 饱和;等磁盘的线程算在 b 列,不在 r。下一步在突发时用 pidstat 1 或 perf 抓是谁(定时任务、批处理、日志压缩),监控改用秒级间隔,或者直接监控饱和度,比如 PSI 的 cpu 一行。
场景:一个请求平均 12 ms。剖析显示其中 3 ms 花在 JSON 序列化上。同事提议换一个号称快 10 倍的序列化库,说「这样请求就能快 10 倍」。
用时间来量化:新耗时 = 12 − 3 + 0.3 = 9.3 ms。收益的上限由被优化部分的占比决定,这和 Amdahl 定律是同一个道理(§2.6.3)。还要确认这 3 ms 是同步地花在请求路径上的:书里提醒,异步做的部分(比如后台刷盘)省下来也不影响请求延迟。剩下的 9 ms 在哪,接着按延迟分析拆。
值得停下来的句子
For every resource, check utilization, saturation, and errors.— §2.5.9。本站译:对每一个资源,查它的利用率、饱和度和错误。
整个 USE 方法就这一句,重点在「每一个」。它从资源清单出发,而不是从手边的工具出发,所以没有工具能回答的问题也会留在清单上,你会知道自己哪里还没看。对 C++ 服务来说,清单上还应该有线程池、锁、连接池、文件描述符上限和容器的 cgroup 限额:这些地方的饱和,CPU 和磁盘的指标看不出来。
Every time you see an average used as a performance metric, especially an average latency, ask: What is the distribution?— §2.8.5。本站译:每次看到用平均值当性能指标,尤其是平均延迟,都要问一句:它的分布是什么样的?
监控大盘、压测报告、SLA 最爱写平均值,因为它只有一个数。问分布的具体做法是:要直方图或热图,至少要 p50、p99 和最大值;看是不是有两个峰、有没有零星的极端值。很多「平均正常、用户却在骂」的问题,答案都在这一问里。
带走的几条
一句话:先问清楚、分清负载还是服务、把资源扫一遍,再沿着延迟往下拆;读数时记住排队和分布。
把「慢」换成一个数:哪类请求、p99 还是平均、从多少到多少;再问最近改了什么。很多问题到这里就有了方向。
§2.5.5请求率平稳、耗时上升:查服务自身。两个一起涨:先当负载问题,看谁在压。
§2.5.10对每个资源按这个顺序查,软件资源(锁、线程池、fd、限额)也算。查不到的指标记下来,那是已知的未知。
§2.5.9服务时间固定时,利用率 60% 平均响应是服务时间的 1.75 倍,80% 是 3 倍;服务时间随机时等待再翻一倍。
§2.6.5双峰时平均值落在谷里;短时突发会被长间隔的平均摊平。要直方图、p99 和秒级数据。
§2.8.512 ms 的请求里能省 3 ms,最多快 1.3 倍。先算上限再动手,挑占比最大的那段。
§2.8.1先写预测再改;没效果就改回去再试下一个,别让说不清来由的配置留在生产上。
§2.5.6