Skip to main content

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% 的用户已经超时了。

分位数分别对应不同层级的长尾延迟

  1. P90 — 日常水位监控
    过滤偶尔的网络抖动,反映大多数「正常偏慢」用户的体感。P90 飙升,通常说明整体负载在加重。

  2. P95 — SLA / SLO 的常用标准
    很多核心业务(如下单、支付)的服务等级目标定在 P95,代表绝大多数用户能接受的延迟上限。

  3. 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(分桶统计)维护 <10ms10~50ms 等桶的计数器,查 P99 时找累计达到 99% 的桶,再插值估算
Sketch / T-Digest用质心保留分布轮廓,基于数据结构直接算分位数,丢弃原始顺序

Grafana 上的 P99 曲线,本质是时间窗口快照:每个请求 O(1) 写入桶 → 窗口结束插值算一次 P99 → 丢弃桶数据,只保留结果。

Node.js 实操注意:生产环境实时统计时,不要把所有耗时 push 到数组再 sort()——流量稍大就会触发严重 GC 卡顿。本地调试可以;生产请用 tdigesthdr-histogram 等分位数库。

一句话:概念上「排了序」,物理上「没排序」。P99 代表「100 个用户里最慢的那 1 个」;底层是排序还是估算,交给监控系统即可。