P90/P95/P99 分位数
P90、P95、P99 是性能监控中最常用的分位数(Percentile,百分位数),用来衡量「在特定比例请求下,耗时最多是多少」。
它们能避开平均值陷阱——性能监控里的经典误区:均值会把少数极端慢请求「摊平」,让你误以为系统整体很快。
分位数怎么算
假设 1 分钟内 API 被调用 1000 次,把所有请求耗时从小到大排序:
| 指标 | 位置 | 含义 |
|---|---|---|
| P90 | 第 900 位 | 90% 的请求比这个值快,10% 更慢 |
| P95 | 第 950 位 | 95% 的请求比这个值快,5% 更慢 |
| P99 | 第 990 位 | 99% 的请求比这个值快,1% 更慢 |
为什么不用平均值
100 个请求里,99 个耗时 1ms,1 个耗时 10 秒,平均耗时约 100ms。看平均值会觉得「系统很快」,但那 1% 的用户已经超时了。
分位数分别对应不同层级的长尾延迟:
-
P90 — 日常水位监控
过滤偶尔的网络抖动,反映大多数「正常偏慢」用户的体感。P90 飙升,通常说明整体负载在加重。 -
P95 — SLA / SLO 的常用标准
很多核心业务(如下单、支付)的服务等级目标定在 P95,代表绝大多数用户能接受的延迟上限。 -
P99 — 揪出隐藏的「性能毛刺」
P99 波动往往来自 GC 暂停、OS 调度、慢 SQL、网络重传等底层问题。优化 P99 是提升稳定性的关键,投入产出比通常很高。
落地建议
- 业务体量较小(QPS < 100):重点看 P95。样本少时 P99 受单次异常影响大,参考意义有限(例如总共 100 个请求,P99 就是最慢的那个,可能只是客户端网络差)。
- 高并发核心链路(支付、登录等):盯 P99,必要时看 P999(99.9%)。0.1% 的超时,在日活规模下也可能影响大量用户。
- 前端页面加载:重点看 P90。浏览器、CDN 带来的长尾较多,P90 更贴近普通用户的真实感知。
- 样本量:计算 P99 建议至少 1000 个数据点,否则数字跳变大,容易误判。监控仪表盘如有「平均值」,可考虑换成 P95。
压测:如何获取分位数
压测是采集 P90/P95/P99 的主要手段。常用工具:
-
autocannon:Node.js 生态的 HTTP 压测工具,适合 API 基准测试。
npx autocannon -c 100 -d 10 http://localhost:3000/api上面命令用 100 并发连接,持续压测 10 秒。
-
wrk / wrk2:底层高性能 HTTP 压测工具;
wrk2支持恒定吞吐量,更适合评估 P95/P99。
更多工具选型见 压测工具。
数学定义 vs 工程实现
数学上,P99 必须对所有请求耗时排序,再取第 990 位的值——不排序就无法知道「第 99% 的点」是多少。
生产环境里,Prometheus、Datadog 等监控系统几乎不会对原始数据做全量排序——每分钟几十万、上百万条请求,全量排序会导致 CPU、内存暴涨甚至 OOM。实际用的是近似算法:
| 方式 | 原理 |
|---|---|
| Histogram(分桶统计) | 维护 <10ms、10~50ms 等桶的计数器,查 P99 时找累计达到 99% 的桶,再插值估算 |
| Sketch / T-Digest | 用质心保留分布轮廓,基于数据结构直接算分位数,丢弃原始顺序 |
Grafana 上的 P99 曲线,本质是时间窗口快照:每个请求 O(1) 写入桶 → 窗口结束插值算一次 P99 → 丢弃桶数据,只保留结果。
Node.js 实操注意:生产环境实时统计时,不要把所有耗时 push 到数组再 sort()——流量稍大就会触发严重 GC 卡顿。本地调试可以;生产请用 tdigest、hdr-histogram 等分位数库。
一句话:概念上「排了序」,物理上「没排序」。P99 代表「100 个用户里最慢的那 1 个」;底层是排序还是估算,交给监控系统即可。
link
-
JMeter 使用可参考 小林coding - JMeter 工具使用