3. 统计学基础:均值、中位数、标准差、百分位数、正态分布与3σ原则
做监控阈值设定,说白了就是跟数据打交道。你连数据的脾气都没摸透,阈值设得再漂亮也是白搭。这一章我们就把几个最核心的统计概念掰开揉碎讲清楚。别怕,不搞数学推导,咱们只聊怎么用。
3.1 均值与中位数:数据的“中心”到底在哪?
先问个问题:你手头有一组响应时间数据,想找个“典型值”代表整体,用均值还是中位数?
均值(Mean),就是算术平均。把所有数加起来除以个数。简单粗暴,但有个致命弱点——它怕“脏数据”。
举个例子:
某接口 10 次调用耗时(ms):[102, 98, 105, 110, 95, 108, 101, 97, 103, 2000]
均值 = (102+98+...+2000)/10 = 291.9 ms
你看,就因为一个 2000ms 的毛刺,均值从 100 左右被拉到了 292。这能代表正常情况吗?显然不能。
中位数(Median),就是把数据从小到大排好,取中间那个数。如果数据个数是偶数,取中间两个的平均。
还是上面那组数据,排序后:[95, 97, 98, 101, 102, 103, 105, 108, 110, 2000]
中位数 = (102+103)/2 = 102.5 ms
看到了吗?中位数几乎不受那个 2000ms 异常值的影响。我个人习惯,在监控数据里,中位数比均值更靠谱。尤其是做 P50 延迟监控时,中位数就是天然的 P50。
我的经验: 有一次排查数据库慢查询,均值显示 200ms,看起来还行。但一查中位数,只有 50ms。说明大部分查询很快,但少数几个“巨慢”的查询把均值拉高了。顺着这个思路,我们很快定位到了几个全表扫描的 SQL。如果只看均值,这个问题可能就被掩盖了。
3.2 百分位数:你不是要“平均”,你是要“保证”
做监控的人,最常听到的就是 P99、P95。这些就是百分位数。
百分位数(Percentile):把数据从小到大排好,第 p 百分位数表示“有 p% 的数据小于等于这个值”。
举个例子:
- P50 = 中位数。一半请求比它快,一半比它慢。
- P95 = 95% 的请求比这个值快。只有 5% 的请求比它慢。
- P99 = 99% 的请求比这个值快。只有 1% 的请求比它慢。
为什么监控里更爱用 P99 而不是均值?
你想想看,一个线上系统,用户感受到的是“最慢的那次”,而不是“平均那次”。P99 能告诉你:在最差的 1% 情况下,系统表现如何。这才是用户体验的真实写照。
| 指标 | 含义 | 监控场景 |
|---|---|---|
| P50(中位数) | 一半请求的延迟 | 系统整体“典型”表现 |
| P95 | 95% 请求的延迟上限 | 大部分用户体验 |
| P99 | 99% 请求的延迟上限 | 长尾问题、异常排查 |
| P99.9 | 99.9% 请求的延迟上限 | 核心链路、金融交易 |
避坑指南: 我曾经在一个高并发系统里直接用 P99 设告警阈值,结果告警满天飞。后来一查,P99 本身波动就很大,尤其是流量低谷期,样本少,P99 会剧烈抖动。后来我改用 P95 + 滑动窗口,才稳定下来。记住:百分位数对样本量敏感,样本太少时别用它。
3.3 标准差与方差:数据到底有多“散”?
均值告诉你中心在哪,但没告诉你数据是聚在一起还是散得到处都是。这时候就需要标准差。
标准差(Standard Deviation, σ):衡量数据偏离均值的程度。标准差越大,数据越分散;标准差越小,数据越集中。
公式不写了,你记住一句话就行:68% 的数据落在均值 ±1σ 范围内,95% 落在 ±2σ 范围内,99.7% 落在 ±3σ 范围内。这就是后面要讲的 3σ 原则的基础。
在监控里,标准差有什么用?
- 判断数据稳定性:CPU 使用率均值 50%,标准差 5%,说明很稳定;标准差 30%,说明波动剧烈。
- 动态阈值的基础:很多自适应阈值算法,本质就是“均值 ± n × 标准差”。
- 识别异常波动:当某个数据点偏离均值超过 3σ,大概率是异常。
实战场景: 监控磁盘 IO 等待时间。正常情况下,均值 10ms,标准差 2ms。突然某时刻 IO 等待飙到 20ms。20ms 离均值 10ms 差了 5 个标准差((20-10)/2=5σ),远超 3σ 范围。这个告警,值得立即响应。
3.4 正态分布与 3σ 原则:异常检测的“黄金法则”
正态分布,就是那个钟形曲线。很多自然现象和工程数据都近似服从正态分布——比如网络延迟、CPU 使用率、内存占用(在稳态下)。
3σ 原则:如果数据服从正态分布,那么:
- 落在 μ±σ 内的概率 ≈ 68.27%
- 落在 μ±2σ 内的概率 ≈ 95.45%
- 落在 μ±3σ 内的概率 ≈ 99.73%
换句话说,一个数据点如果偏离均值超过 3σ,它发生的概率不到 0.3%。这在统计学上被称为“小概率事件”,在监控里,我们就把它当作异常。
我的习惯: 做阈值设定时,我一般先用 3σ 作为初始阈值。如果告警太多,就放宽到 4σ;如果漏报太多,就收紧到 2.5σ。但注意,3σ 原则的前提是数据近似正态分布。如果数据是偏态的(比如长尾延迟),直接用 3σ 会误报很多。这时候我会先做数据变换(比如取对数),或者改用百分位数法。
下面这张图,把这一章的核心逻辑串起来了:
3.5 实战:用 Python 快速计算这些指标
理论讲完了,来点实际的。假设你有一组 CPU 使用率数据,想快速算一下这些指标:
import numpy as np
# 模拟 1000 个 CPU 使用率数据(近似正态分布)
data = np.random.normal(loc=60, scale=10, size=1000)
# 均值与中位数
mean_val = np.mean(data)
median_val = np.median(data)
print(f"均值: {mean_val:.2f}, 中位数: {median_val:.2f}")
# 标准差
std_val = np.std(data)
print(f"标准差: {std_val:.2f}")
# 百分位数
p50 = np.percentile(data, 50)
p95 = np.percentile(data, 95)
p99 = np.percentile(data, 99)
print(f"P50: {p50:.2f}, P95: {p95:.2f}, P99: {p99:.2f}")
# 3σ 上下界
upper_3sigma = mean_val + 3 * std_val
lower_3sigma = mean_val - 3 * std_val
print(f"3σ 上界: {upper_3sigma:.2f}, 3σ 下界: {lower_3sigma:.2f}")
# 检查有多少数据超出 3σ
outliers = data[(data > upper_3sigma) | (data < lower_3sigma)]
print(f"超出 3σ 的数据点数量: {len(outliers)}")
小技巧: 实际生产环境里,我不会直接用 numpy 算全量数据。数据量太大时,我会用 在线算法(比如 Welford 算法)来增量计算均值和标准差,或者用 T-Digest 算法来近似计算百分位数。这些在 Prometheus、Datadog 等监控系统里都有内置实现。
3.6 这一章的核心,就三句话
- 选对“中心”:数据有毛刺时,中位数比均值更可靠。
- 关注“尾部”:P95/P99 比均值更能反映真实用户体验。
- 用好“3σ”:数据近似正态时,3σ 是简单有效的异常检测基线。