CPU 利用率 80%,看起来还有余量——但调度延迟已经让关键 Pod 的请求排队数百毫秒。这种"利用率正常、实际已经卡死"的盲区,在 Kubernetes 里长期存在。v1.36 中 PSI(Pressure Stall Information)指标从 Beta 晋升 GA,意味着你终于有一个稳定接口,直接观测节点、Pod、容器三个层面的资源阻塞,而不是靠利用率猜。
利用率为什么会骗人
传统监控看的是"用了多少":CPU 百分比、内存占用率。问题在于,利用率低不代表没有压力。一个 4 核节点 CPU 利用率 60%,如果其中两个核被批处理任务占满、另外两个核上的交互服务在调度队列里等待,用户体验已经恶化——但利用率曲线一切正常。
PSI 的思路完全不同:它不问"用了多少",而是问"有多少时间被浪费在等待上"。内核从 2018 年开始提供 PSI,现在 Kubernetes 把这套信号正式接入了可观测体系。PSI 提供两类数据:
- 累计总量(Cumulative Totals):任务处于阻塞状态的绝对时间,适合做趋势分析。
- 滑动平均(Moving Averages):10 秒、60 秒、300 秒三个窗口,帮你区分瞬时抖动和持续压力。60 秒窗口突然跳到 5% 以上,基本可以确认资源饱和正在发生。
开销实测:高密度场景下的两次对照
可观测功能晋升 GA,最常被问的就是"开它要付出多少资源"。SIG Node 在 4 核机器、80+ Pod 密度下做了两组对照实验,结论很明确。
Kubelet 采集开销
第一组实验:内核 PSI 已开启(psi=1),对比 Kubelet Feature Gate 开关对资源使用的影响。
结果:Kubelet CPU 使用曲线在开启和关闭状态下几乎完全重叠,同步的波动在幅度和频率上一致。额外开销稳定在 0.1 核以内,约占节点总容量 2.5%,完全融入 Kubelet 常规的 housekeeping 周期。系统级 CPU 开销同样如此——操作系统本身在跟踪 PSI 大约消耗 2.5 核,Kubelet 去读 cgroup 指标带来的增量可以忽略。
内核跟踪开销
第二组实验:对比 psi=1 和 psi=0 的内核开销,隔离出操作系统层面的记账成本。
在高 I/O 和 CPU 负载、80 Pod 密度下,系统 CPU 增量稳定在 0.037–0.125 核(0.925%–3.125%)。出现过一次 0.225 核(5.6%)的瞬时尖峰,几秒内回落。Kubelet 作为主要采集进程,周期性扫描 cgroup 层级时的 CPU 使用始终低于 0.25 核(6.25%),且尖峰不超过 1 秒。
结论:无论内核层还是 Kubelet 层,PSI 的开销都足够低,不需要在高密度节点上犹豫是否开启。
Beta 到 GA 之间修掉的一个坑
v1.34 Beta 版有一个容易踩的陷阱:如果 Kubelet Feature Gate 开了 PSI,但底层内核不支持(psi=0 或内核版本太旧),Kubelet 会输出全零指标。监控系统看到零值,可能误判为"没有压力"而非"指标不可用",触发误报或漏报。
v1.36 GA 版修复了这个问题:Kubelet 在采集前先检测 cgroup 配置,确认 OS 层面确实支持 PSI,才输出指标;不支持时直接不发射,避免零值污染告警链路。
快速上手:采集与查询 PSI 指标
前置条件
| 条件 | 要求 |
|---|---|
| Linux 内核版本 | ≥ 4.20 |
| cgroup 版本 | v2 |
| 内核编译选项 | CONFIG_PSI=y |
| 启动参数 | 不能带 psi=0 |
| Kubernetes 版本 | ≥ v1.36(GA,无需 Feature Gate) |
先确认节点内核支持:
# 检查内核版本
uname -r
# 检查 cgroup 版本(v2 路径包含 "cgroup2_fs" 或挂载点为 /sys/fs/cgroup)
mount | grep cgroup2
# 检查 PSI 是否在内核中启用
cat /proc/pressure/cpu
# 如果输出类似 "some avg10=0.00 avg60=0.00 avg300=0.00 total=0" 说明已启用
# 如果报错 "No such file or directory" 说明内核未开启 PSI
通过 Prometheus 采集
Kubelet 的 /metrics/cadvisor 端点现在包含 PSI 指标,Prometheus 直接抓取即可。在 Prometheus 配置中添加:
scrape_configs:
- job_name: 'kubernetes-cadvisor'
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- target_label: __metrics_path__
replacement: /metrics/cadvisor
- source_labels: [__address__]
regex: '(.*):10250'
target_label: __address__
replacement: '${1}:10250'
部署后,在 Prometheus 中查询 PSI 相关指标名(以 psi 为关键词搜索),你会看到 container_cpu_psi_some_seconds_total、container_memory_psi_some_seconds_total 等指标,覆盖 CPU、Memory、I/O 三个维度,分别有 some(部分任务阻塞)和 full(全部任务阻塞)两个级别。
通过 Summary API 实时查询
如果你是节点管理员,可以通过控制面代理到 Kubelet HTTP API,直接拿到某个容器的实时 PSI 数据:
# 设置你要查询的容器名
CONTAINER_NAME="example-container"
# 通过 API Server 代理查询该容器的 CPU / Memory / I/O PSI 数据
kubectl get --raw "/api/v1/nodes/$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')/proxy/stats/summary" \
| jq '.pods[].containers[] | select(.name=="'$CONTAINER_NAME'") | {name, cpu: .cpu.psi, memory: .memory.psi, io: .io.psi}'
⚠️ 注意:代理到 Kubelet 是特权操作,存在安全风险。只在有明确管理权限时使用,不要在日常监控流水线中依赖这种方式。
一个基于 PSI 的告警规则示例
利用 PSI 的 60 秒滑动平均,可以写一条比利用率告警更精准的规则:
groups:
- name: psi-alerts
rules:
# 内存阻塞持续超过阈值——比 "内存利用率 > 85%" 更可靠
- alert: MemoryPressureStallDetected
expr: container_memory_psi_some_seconds_total / container_memory_psi_some_seconds_created > 0.05
for: 2m
labels:
severity: warning
annotations:
summary: "容器 {{ $labels.container }} 在 Pod {{ $labels.pod }} 中出现持续内存阻塞"
description: "过去 2 分钟内,该容器约 5% 的时间因内存压力处于阻塞状态,可能需要扩容或调整资源限制。"
上述规则中的表达式需要根据你实际采集到的指标名和标签调整。
some_seconds_total是累计值,实际告警通常需要用rate()或increase()函数计算窗口内的阻塞比例。以下是一个更实用的写法:
- alert: MemoryPressureStallDetected
expr: rate(container_memory_psi_some_seconds_total[1m]) > 0.05
for: 2m
这表示:过去 1 分钟内,每秒有超过 5% 的时间任务因内存阻塞被 stall,持续 2 分钟即告警。
采纳建议与注意事项
- Windows 节点不适用:PSI 是 Linux 内核特性,Windows 节点上 Kubelet 会直接跳过 PSI 指标。混合集群中,Windows 节点的监控需要走其他路径。
- 先看内核版本再升级:GKE COS 默认
psi=1,但部分自建节点可能用旧内核或psi=0启动参数。升级 K8s 到 v1.36 之前,先跑一遍前文的检查命令。 - 不要立刻替换利用率告警:PSI 和利用率是互补关系。利用率告诉你"还剩多少余量",PSI 告诉你"阻塞有多严重"。建议先并行观察一段时间,建立 PSI 基线,再逐步将关键告警从利用率切换到 PSI。
full比some更严重:some表示至少一个任务在等待,full表示所有任务都在等待——后者意味着整个 cgroup 已经实质停摆,优先关注full指标。
PSI 指标从 v1.33 Alpha、v1.34 Beta 到 v1.36 GA,走了三个版本。现在接口稳定、开销可控、零值陷阱已修复——如果你的节点满足内核条件,开起来没有理由再等。