开始前,会这些就够了
- 会读取简单列表和平均数
遇到不熟悉的词,先看这 2 个解释
- 吞吐量
- 单位时间内处理的工作数量,例如每秒完成多少请求或每分钟处理多少任务;比较前要写清统计窗口、工作类型,以及失败的尝试是否也被计入。
- 延迟与 p99
- 延迟是一次操作从指定起点到终点经历的时间;把多次耗时排序后,p99 描述接近百分之九十九位置的耗时,用来观察较慢请求的情况。
假设两套接口的平均响应时间都接近三十毫秒。第一套每次都差不多快;第二套大多数时候很快,却偶尔停顿一秒。平均数把这些差异压成一个数,所以“平均相同”并不等于用户体验相同。下面的数据全是人为构造,用来观察统计量,不是某个服务的测评。
只看平均数,会漏掉谁?
- 平均
- 29.8 ms
- p95
- 10 ms
- p99
- 1000 ms
- 最大值
- 1000 ms
试着把慢请求从 20 个改成 10 个,再改成 1 个。p99 还会不会显示最慢的那次?
固定 1,000 个假设请求,普通请求为 10 毫秒。分位数采用最近秩法(向上取整位置),没有监控采样或直方图估计。这里的数字不是服务性能测量。
先把请求排成一列
把响应时间从短到长排序,就能问:排在百分之九十五位置的请求用了多久?这个值常写成 p95。它是一个时间阈值,不是“最慢百分之五请求的平均时间”。不同软件可能采用插值等不同定义。本实验先把样本数乘以 0.95,将结果向上取整,再取排序后对应位置的值;位置从 1 开始计数。
分位数要带着请求数量和时间范围一起读。一小时的 p99 不能直接代表某一分钟,几十个请求得出的高分位数也可能非常不稳定。它帮助描述慢尾巴,但不会自动解释原因;排队、锁等待、磁盘、网络或下游调用,都需要更多证据区分。
用同一个平均值造出不同体验
模型 A 的一千个请求都耗时二十九点八毫秒;模型 B 有九百八十个请求耗时十毫秒,其余二十个耗时一千毫秒。两者总时间相同,因此平均数相同。运行程序时,关注 p95 和 p99 是否给出了同样的判断。
这里直接保存全部样本并排序,得到的是这份有限列表按指定定义计算的结果。线上监控通常不能无限保存所有原始请求,会用直方图等结构统计分布,算出的分位数可能是估计值,精度取决于所用算法和配置。
from math import ceil
samples = {"A": [29.8] * 1000, "B": [10] * 980 + [1000] * 20}
def percentile(values, p):
ordered = sorted(values)
return ordered[ceil(p * len(ordered)) - 1]
for name, values in samples.items():
print(name, "mean", round(sum(values) / len(values), 1),
"p95", percentile(values, 0.95),
"p99", percentile(values, 0.99))
怎样运行:Python 3.10+;保存为 latency_demo.py,运行 python latency_demo.py。
运行后对照结果
A mean 29.8 p95 29.8 p99 29.8
B mean 29.8 p95 10 p99 1000
用户等的是整件事完成
一次页面展示可能同时请求商品、库存和推荐。如果页面必须等它们全部完成,最慢的那个就可能决定这一轮等待时间。调用次数越多,某次慢请求参与其中的机会也会改变;但不能不看依赖关系,就把各接口的 p99 相加或相乘当成页面 p99。
也要区分快速失败和快速成功。若大量请求立即报错,平均响应时间反而可能变小,系统却更不可用。观察时同时记录成功率、超时数量和端到端耗时,并说明计时是否包含连接池等待、重试与客户端网络。少记了一段等待,图表仍会很好看。
几台机器的 p99 不能直接求平均
每台机器的 p99 只是它自己分布上的一个点,没有告诉你其他请求在哪里。把这些点平均,无法恢复所有请求混在一起后的排序。请求量不同还会让问题更明显:一台只接十个请求,另一台接十万个,它们也不该在整体平均耗时里被等权看待。
需要整体分位数时,保留可合并的分布信息,例如兼容的直方图桶;需要整体平均值时,汇总耗时总和与请求总数后相除。最后按真实目标观察“多少成功请求在规定时间内完成”,让数字对应到用户完成的动作。
记住这三点
- 平均相同的两组请求,可以有完全不同的慢请求分布。
- p99 是分布位置对应的阈值,要说明算法、样本数和时间范围。
- 跨实例汇总分位数需要分布信息,不能直接平均各自的 p99。
别把例子用过头
- 人为列表只能解释统计关系,不能作为吞吐量或真实性能证据。
- 本例的排序分位数和监控平台的估计值可能不同。
- 只统计成功且未超时的请求,可能漏掉用户等待最久的部分。
自己试一小步
如果只剩一个请求耗时一千毫秒,p99 还一定能揭示它吗?
- 保持一千个请求总数,改变慢请求数量并记录平均值、p95、p99。
- 再加一个最大耗时指标,比较它与 p99 的敏感程度。
- 写出你为“用户等太久”选择的两个指标和观察窗口。
做到这些,就算完成
- 能用“样本数乘以所求比例,再向上取整”独立检查计算位置。
- 没有把 p99 当成最坏情况保证。
- 指标中包括请求量或成功/失败信息。
查原始资料
想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。
- Monitoring Distributed Systems (新标签页)↗
支持观察延迟分布、区分成功与失败延迟,以及延迟、流量、错误和饱和度。
- Histograms and summaries (新标签页)↗
支持分位数与直方图、估计误差、跨实例不能直接平均分位数和总和/计数平均。
找一份资料继续练
先选一项,按下面的范围继续学;不必从头读完整门课程。
OpenTelemetry 官方:Java 自动插桩与遥测 (新标签页)↗
只练把请求和追踪记录对应起来,保留几次慢请求的耗时与经过的步骤,再检查平均值遗漏了哪些等待。
查看学习准备与访问说明 →