P99 是如何计算的?

简介: P99 是如何计算的?


Latency(延迟)是我们在监控线上的组件运行情况的一个非常重要的指标,它可以告诉我们请求在多少时间内完成。监控 Latency 是一个很微妙的事情,比如,假如一分钟有 1亿次请求,你就有了 1亿个数字。如何从这些数字中反映出用户的真实体验呢?

之前的公司用平均值来反应所有有关延迟的数据,这样的好处是计算量小,实施简单。只需要记录所有请求的一个时间总和,以及请求次数,两个数字,就可以计算出平均耗时。

但问题是,平均耗时非常容易掩盖真实的问题。比如现在有 1% 的请求非常慢,但是其余的请求很快,那么这 1% 的请求耗时会被其他的 99% 给拉平,将真正的问题掩盖。

所以更加科学的一种监控方式是观察 P99/P95/P90 等,叫做 Quantile。简单的理解,P99 就是第 99% 个请求所用的耗时。假如 P99 现在是 10ms,那么我们可以说 “99% 的请求都在 10ms 内完成”。虽然在一些请求量较小的情况下,P99 可能受长尾请求的影响。但是由于 SRE 一般不会给在量小的业务上花费太多精力,所以这个问题并不是很大。

但是计算就成了一个问题。P99 是计算时间的分布,所以我们是否要保存下来 1 亿个请求的时间,才能知道第 99% 的请求所用的时间呢?

这样耗费的资源太大了。考虑到监控所需要的数据对准确性的要求并不高。比如说 P99 实际上是 15.7ms 但是计算得到数据是 15.5ms,甚至是 14ms,我认为都是可以接受的。

我们关注更多的是它的变化。“P99 耗时从 10.7ms 上涨到了 14ms” 和 “P99耗时从 11ms 上涨到了 15.5ms” 这个信息对于我们来说区别并不是很大。(当然了,如果是用于衡量服务是否达到了服务等级协议 SLO 的话,还是很大的。这样需要合理地规划 Bucket 来提高准确性)。

所以基于这个,Prometheus 采用了一种非常巧妙的数据结构来计算 Quantile: Histogram。

Histogram 本质上是一些桶。举例子说,我们为了计算 P99,可以将所有的请求分成 10 个桶,第一个存放 0-1ms 完成的请求的数量,后面 9 个桶存放的请求耗时上区间分别是 5ms、10ms、50ms、100ms、200ms、300ms、500ms、1s、2s,这样只要保存 10 个数字就可以了。

要计算 P99 的话,只需要知道第 99% 个数字落在了哪一个桶,比如说落在了 300ms-500ms 的桶,那我们就可以说现在的 99% 的请求都在 500ms 之内完成(这样说不太准确,如果准确的说,应该是第 99% 个请求在 300ms – 500ms 之间完成)。这些数据也可以用来计算 P90、P95 等等。

由于我们的监控一般是绘制一条曲线,而不是一个区间。所以 P99 在 300-500 之间是不行的,需要计算出一个数字来。

Prometheus 是假设每一个桶内的数据都是线性分布的,比如说现在 300-500 的桶里面一共有 100 个请求,小于300个桶里面一共有 9850 个请求。所有的桶一共有 1万个请求。

那么我们要找的 P99 其实是第 10000 * 0.99 = 9900 个请求。第 9900 个请求在 300-500 的桶里面是第 9900 – 9850 = 50 个请求。根据桶里面都是线性分布的假设,第 50 个请求在这个桶里面的耗时是 (500 – 300) * (50/100) = 400ms,即 P99 就是 400ms。

可以注意到因为是基于线性分布的假设,不是准确的数据。比如假设 300-500 的桶中耗时最高的请求也只有 310ms,得到的计算结果也会是 400ms。桶的区间越大,越不准确,桶的区间越小,越准确。

写这篇文章,是因为昨天同事跑来问我,“为啥我的日志显示最慢的请求也才 1s 多,但是这个 P999 latency 显示是 3s?”

我查了一下确实如他所说,但是这个结果确实预期的。因为我们设置的桶的分布是:10ms、50ms、100ms、500ms、1s、5s、10s、60s。

如上所说,Prometheus 只能保证 P999 latency 落在了 1s – 5s 之间,但不能保证误差。

如果要计算准确的 Quantile,可以使用 Summary 计算。简单来说,这个算法没有分桶,是直接在机器上计算准确的 P99 的值,然后保存 P99 这个数字。但问题一个是在机器本地计算,而不是在 Prometheus 机器上计算,会占用业务机器的资源;另一个是无法聚合,如果我们有很多实例,知道每一个实例的 P99 是没有什么意义的,我们更想知道所有请求的 P99。显然,原始的信息已经丢失,这个 P99 per instance 是无法支持继续计算的。

另外一个设计巧妙的地方是,300-500 这个桶保存的并不是 300-500 耗时的请求数,而是 <500ms 的请求数。也就是说,后面的桶的请求数总是包含了它前面的所有的桶。这样的好处是,虽然我们保存的数据没有增加(还是10个数字),但是保存的信息增加了。假如说中间丢弃一个桶,依然能够计算出来 P99,在某些情况下非常有用,比如监控资源不够了,我们可以临时不收集前5个桶,依然可以计算 P99。



相关文章
|
2月前
|
人工智能 安全 架构师
2025云栖大会 | 阿里云网络技术Session主题资料和视频回放归档
2025年9月24日-26日,杭州,一年一度的云栖大会如期而至;阿里云飞天洛神云网络作为阿里云计算的连接底座,是飞天云操作系统的核心组件,致力于为上云企业提供高可靠、高性能、高弹性、智能的连接服务。本次云栖,云网络产品线也带来全系列产品升级,以及创新技术重磅解读,围绕增强确定性、提效自动化、深耕智能化和敏捷全球化带来技术、产品和服务升级,以及全新的云网络产品生态合作计划发布。
512 2
|
存储 域名解析 NoSQL
『MongoDB』MongoDB高可用部署架构——分片集群篇(Sharding)
📣读完这篇文章里你能收获到 - 为什么要使用分片 - Mongodb分片集群有哪些特点 - Mongodb分片集群的完整架构 - Mongodb分片集群数据分布方式 - Mongodb分片集群的设计思路 - Mongodb分片集群搭建及扩容 - 这篇文章强烈建议收藏!!!免得下次找不到
4883 2
『MongoDB』MongoDB高可用部署架构——分片集群篇(Sharding)
|
Oracle Java 关系型数据库
在 macOS 上安装 JDK 17
在 macOS 上安装 JDK JDK 支持基于 Intel (x64) 和 Apple Silicon (AArch64) 的 Mac 电脑。 本主题包括以下部分: 在 macOS 上安装 JDK 的系统要求 macOS JDK 安装说明符号 确定 macOS 上的默认 JDK 版本 在 macOS 上安装 JDK 在 macOS 上卸载 JDK macOS 安装常见问题
9136 0
|
Java 数据库连接 数据库
|
12月前
|
缓存 NoSQL Serverless
云数据库Tair:从稳定低延时缓存到 Serverless KV
本次分享聚焦云数据库Tair的使用,涵盖三部分内容:1) Tair概览,介绍其作为稳定低延时缓存及KV数据库服务的特点和优势;2) 稳定低延迟缓存技术,探讨如何通过多线程处理、优化内核等手段提升性能与稳定性;3) 从缓存到Serverless KV的演进,特别是在AI大模型时代,Tair如何助力在线服务和推理缓存加速。Tair在兼容性、性能优化、扩缩容及AI推理加速方面表现出色,满足不同场景需求。
|
11月前
|
缓存 NoSQL 调度
Tair:基于KV缓存的推理加速服务
Tair 是阿里云基于KV缓存的推理加速服务,旨在优化大模型推理过程中的性能与资源利用。内容分为三部分:首先介绍大模型推理服务面临的挑战,如性能优化和服务化需求;其次讲解Nvidia TensorRT-LLM推理加速库的特点,包括高性能、功能丰富和开箱即用;最后重点介绍基于KVCache优化的推理加速服务,通过Tair的KV缓存技术提升推理效率,特别是在处理长上下文和多人对话场景中表现出色。整体方案结合了硬件加速与软件优化,实现了显著的性能提升和成本降低。
1057 3
|
存储 网络协议 Java
Tomcat详解(十)——Tomcat性能调优
Tomcat详解(十)——Tomcat性能调优
534 1
|
Java 测试技术 Maven
Maven打包使用多线程加速构建过程
Maven打包使用多线程加速构建过程
2359 0