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σ 原则 偏态/长尾 → 百分位数法 动态告警阈值

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 这一章的核心,就三句话

  1. 选对“中心”:数据有毛刺时,中位数比均值更可靠。
  2. 关注“尾部”:P95/P99 比均值更能反映真实用户体验。
  3. 用好“3σ”:数据近似正态时,3σ 是简单有效的异常检测基线。