2、PSI指标详解:CPU、内存、IO三种资源的PSI指标含义与数据格式
PSI(Pressure Stall Information)是 Linux 内核 4.20 引入的度量机制,用于量化系统资源(CPU、内存、IO)的竞争程度。与传统的系统负载(Load Average)不同,PSI 能够精确区分“任务在等待资源”的时间比例,从而直接反映延迟尖峰的根因。
2.1 PSI 的核心设计思想
PSI 通过跟踪任务在可运行队列(runnable)或不可中断睡眠(IO 等待)状态下的等待时间,计算资源短缺导致的“压力”百分比。其核心指标分为两类:
- some:至少有一个任务因资源不足而等待的时间占比。
- full:所有任务都因资源不足而等待的时间占比(即系统完全停滞)。
关键理解: “some” 表示资源存在竞争,但系统仍在部分运行;“full” 表示资源已被完全耗尽,系统吞吐量降为零。在延迟尖峰告警中,“full” 指标通常比 “some” 更具告警价值。
2.2 三种资源的 PSI 指标含义
| 资源类型 | some 含义 | full 含义 | 典型场景 |
|---|---|---|---|
| CPU | 至少一个任务因 CPU 时间片不足而等待 | 所有可运行任务都在等待 CPU(通常不会发生,因为 idle 任务存在) | 计算密集型任务争抢、调度延迟、CGroup 限制 |
| 内存 (IO) | 至少一个任务因内存页回收或 swap 而等待 | 所有任务都在等待内存资源(系统几乎无响应) | 内存泄漏、OOM 前兆、swap 风暴、大页分配失败 |
| IO | 至少一个任务因块设备 IO 完成而等待 | 所有任务都在等待 IO 完成(系统完全阻塞) | 磁盘性能瓶颈、文件系统锁、存储网络延迟 |
注意: CPU 的 “full” 指标在大多数系统中始终为 0,因为 Linux 调度器保证至少有一个 idle 任务可运行。因此,CPU 压力告警应主要关注 “some” 指标,而内存和 IO 的 “full” 指标才是真正的“系统挂起”信号。
2.3 PSI 数据格式与文件结构
PSI 数据通过 /proc/pressure/ 目录下的三个伪文件暴露:
/proc/pressure/cpu
/proc/pressure/memory
/proc/pressure/io
每个文件的内容格式如下(以 /proc/pressure/cpu 为例):
some avg10=0.00 avg60=0.00 avg300=0.00 total=0
full avg10=0.00 avg60=0.00 avg300=0.00 total=0
字段说明:
- avg10 / avg60 / avg300:过去 10 秒、60 秒、300 秒的平均压力百分比(浮点数,精确到小数点后两位)。
- total:自系统启动以来的累计等待时间(微秒,单调递增)。
数据精度: avg10 用于快速检测瞬时尖峰,avg60 用于短期趋势,avg300 用于长期基线。在延迟尖峰告警中,avg10 是最敏感的指标,通常设置 0.1%~1% 的阈值即可捕获异常。
2.4 PSI 指标与延迟尖峰的关联
下图展示了 PSI 指标如何映射到应用延迟的恶化过程:
2.5 PSI 数据读取与解析示例
以下 Python 代码演示如何读取并解析 PSI 指标:
import re
def read_psi(resource):
"""读取指定资源的 PSI 指标"""
path = f"/proc/pressure/{resource}"
with open(path, 'r') as f:
data = f.read()
return data
def parse_psi(data):
"""解析 PSI 数据为结构化字典"""
result = {}
for line in data.strip().split('\n'):
parts = line.split()
metric_type = parts[0].rstrip(':') # 'some' 或 'full'
avg10 = float(parts[1].split('=')[1])
avg60 = float(parts[2].split('=')[1])
avg300 = float(parts[3].split('=')[1])
total = int(parts[4].split('=')[1])
result[metric_type] = {
'avg10': avg10,
'avg60': avg60,
'avg300': avg300,
'total': total
}
return result
# 示例:读取内存 PSI
psi_data = read_psi('memory')
parsed = parse_psi(psi_data)
print(f"Memory some avg10: {parsed['some']['avg10']}%")
print(f"Memory full avg10: {parsed['full']['avg10']}%")
2.6 PSI 指标在延迟尖峰告警中的使用建议
| 资源 | 推荐告警指标 | 典型阈值(avg10) | 说明 |
|---|---|---|---|
| CPU | some | > 5% | CPU 竞争通常不会导致 full,some 即可反映调度延迟 |
| 内存 | full | > 0.5% | 内存 full 意味着任务被阻塞在回收路径,延迟影响极大 |
| IO | full | > 1% | IO full 表示所有任务都在等待磁盘,系统几乎停滞 |
最佳实践: 在设置告警阈值时,建议先收集 7 天的基线数据,以 avg10 的 P95 值作为参考。对于延迟敏感型服务(如数据库、消息队列),阈值应比通用服务更严格(例如内存 full avg10 > 0.1% 即告警)。
2.7 PSI 与 cgroup v2 的集成
在 cgroup v2 环境下,PSI 指标同样适用于容器级别。每个 cgroup 的 PSI 数据位于:
/sys/fs/cgroup/<cgroup_path>/cpu.pressure
/sys/fs/cgroup/<cgroup_path>/memory.pressure
/sys/fs/cgroup/<cgroup_path>/io.pressure
数据格式与系统级完全一致。这使得我们可以精确监控单个容器或 Pod 的资源压力,避免“邻居效应”导致的误告警。
注意: cgroup v2 的 PSI 指标默认启用,无需额外内核参数。但需要确保内核版本 >= 4.20,且 cgroup 文件系统已挂载为 v2 模式。