登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

Linux pressure stall information 怎样定位资源等待

来源:17golang原创

时间:2026-11-03 12:37:19 437浏览 收藏

遇到接口延迟突然升高、批处理吞吐下降时,我通常不会先把问题归咎于“CPU 太高”。Linux 的 pressure stall information(PSI)更适合回答另一个问题:有多少任务因为 CPU、内存或 I/O 资源暂时拿不到而在等待。查看 /proc/pressure/cpu、/proc/pressure/memory 和 /proc/pressure/io 后,再把压力趋势与业务日志、负载指标对齐,才能把“系统变慢”缩小为具体资源等待。

定位 PSI 的核心是先区分资源和压力层次,再观察 10 秒、60 秒、300 秒趋势;some 表示至少有部分任务在等,full 表示所有非空闲任务同时被该资源卡住。PSI 是争用信号,不是单独的根因证明。

先确认 PSI 文件是否真的可读

系统级 PSI 通过 proc 文件系统提供三个资源入口。先只读取文本,不要把目录不存在、权限错误和指标为零混成同一种情况。

# 查看三个系统级 PSI 接口;缺少某个文件时要记录为“接口不可用”,不能当作压力为零
for resource in cpu memory io; do
    path="/proc/pressure/${resource}"
    if [ -r "$path" ]; then
        echo "--- $path ---"
        sed -n '1,2p' "$path"
    else
        echo "不可读:$path"
    fi
done

正常输出通常包含 some 和 full 两行,每行有 avg10、avg60、avg300 与 total。这里的“可读”只说明接口能返回数据,不说明业务已经找到根因。

Linux PSI 将 CPU、memory、io 资源映射到 some 和 full 指标的静态关系说明图
图1:PSI 资源入口、压力层次与时间窗口的结构说明图,不是终端截图或运行证据。

读懂 some、full 和三个时间窗口

some 统计的是至少有一部分任务在该资源上停顿的时间占比;系统仍可能有其他任务在工作。full 则表示所有非空闲任务同时处于该资源停顿状态,这时实际 CPU 周期没有用于有效工作,持续出现通常比单纯的 some 更值得优先处理。

avg10、avg60、avg300 是最近 10 秒、60 秒和 300 秒窗口的百分比趋势,适合区分短时尖峰与持续压力;total 是累计停顿时间,单位为微秒,适合记录一次采样以来是否持续累积等待。读数应该按同一时刻保存,避免只看一个字段。

观察点它回答什么不要怎样解读
资源文件CPU、内存还是 I/O 更像等待来源不能凭文件名断言具体进程
some是否有部分任务被资源拖住不能直接等同于系统已不可用
full是否出现所有非空闲任务同时被拖住不能跳过业务和设备层证据
avg10/60/300压力是瞬时、持续还是长周期不能拿不同时间采样直接比较
total停顿是否继续累积不能当成百分比或单次延迟

把 PSI 指标和业务现象对齐

PSI 的价值在于把“资源紧张”变成可比较的信号,但下一步仍要回到对应资源的证据。例如 memory 的 some 上升,可以与回收、分配失败、工作集变化或容器内存限制一起看;io 压力升高时,再对照设备延迟、队列深度和具体进程;cpu 压力升高时,结合运行队列、线程并发和调度行为判断是计算量增长还是被其他任务争用。

我会固定保存三类信息:采样时间、三个窗口的 PSI 原文、同时间段业务延迟或吞吐。这样能区分“PSI 先升高导致业务变慢”和“业务流量先升高、随后资源压力增加”,避免只截取故障时刻的一行数字。

# 以固定间隔保存原始文本,便于和业务时间线对齐;不修改内核接口内容
stamp=$(date -u +%Y%m%dT%H%M%SZ)
out="/tmp/psi-${stamp}.txt"
for resource in cpu memory io; do
    echo "[$resource]" >> "$out"
    cat "/proc/pressure/${resource}" >> "$out"
done
echo "采样文件:$out"

用触发器捕获短时压力尖峰

平均值适合趋势,短时尖峰则可以使用 PSI trigger。官方格式是 。例如 some 150000 1000000 表示在任意 1 秒窗口内,部分内存停顿累计达到 150 毫秒时通知。

触发器绑定在打开的 PSI 文件描述符上,程序需要保持该描述符并用 poll()、select() 或 epoll() 等待;描述符关闭后触发器会注销。下面的示例只展示监控关系,不代表文章环境已经执行过。

#include 
#include 
#include 
#include 
#include 

int main(void) {
    // 1 秒窗口内累计 150 毫秒的部分内存停顿才唤醒
    const char trigger[] = "some 150000 1000000";
    struct pollfd event = {0};

    // 使用 O_NONBLOCK,避免注册或读取时把监控线程卡住
    event.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK);
    if (event.fd 

内核接受的窗口范围是 500 毫秒到 10 秒,监控更新间隔也因此有上下限;无特权用户创建监视器时,窗口还必须是 2 秒的倍数。阈值不要凭感觉设置,先用平均值和历史样本观察,再让触发器承担告警或降级入口。

Linux PSI 触发器与 cgroup pressure 文件之间的静态关系说明图
图2:PSI 触发器、事件等待和 cgroup 压力接口的结构说明图,不是实际监控界面。

下钻到 cgroup 并保留复查边界

如果系统级 PSI 只告诉你“整台机器有等待”,但服务运行在 cgroup v2 中,可以继续看对应 cgroup 目录里的 cpu.pressure、memory.pressure 和 io.pressure。它们与系统级接口使用同样的格式,也可以配置每个 cgroup 的 PSI monitor。

这个下钻动作解决的是归属问题,不是自动给出根因。仍需把 cgroup 的压力时间与服务请求、批任务、容器限制或设备指标对齐。记录以下复查信息,下一次故障才有可比性:

  • 读取的是系统级文件还是哪个 cgroup 的 pressure 文件;
  • 保存了哪个资源、哪个 some/full 行和哪个时间窗口;
  • 触发器的阈值、窗口、注册时间以及描述符是否保持打开;
  • 同时段的业务延迟、吞吐、错误率和资源专属指标。

常见判断误区

只看 CPU 使用率。 CPU 使用率高不等于 CPU pressure 一定高;反过来,任务等待也可能来自内存或 I/O。应先看三类 PSI,再选择对应的专属指标。

看到 full 就直接扩容。 full 表示所有非空闲任务同时停顿的压力状态,确实值得优先关注,但扩容、限流、迁移任务或降低批任务优先级仍要根据业务目标和其他证据决定。

把 avg10 当成单次请求耗时。 avg10 是最近 10 秒的停顿时间占比,不是某条请求的 P99,也不能代替应用级 tracing。

用一次采样下结论。 PSI 的窗口和累计量都需要时间上下文。短时峰值可以用 trigger 捕获,持续问题则应保存多个采样点并与业务时间线对齐。

结语:先用 PSI 找到等待资源,再决定动作

这套方法的落点很简单:先确认 /proc/pressure 是否可读,按资源查看 some/full 和三个窗口,再用同时间的业务证据判断等待是否相关;只有平均值抓不住短峰时才注册 trigger,只有系统级归属不够时才下钻 cgroup。这样 PSI 才是定位链条中的一个可靠观测面,而不是替代日志、追踪和资源专属指标的万能答案。

相关问题

PSI 的 total 为什么不是百分比?

total 是累计停顿时间,单位为微秒;百分比趋势看 avg10、avg60 和 avg300。

some 和 full 应该优先看哪一个?

先同时看两者:some 反映部分任务等待,full 反映所有非空闲任务同时等待。持续 full 通常更严重,但仍要结合资源类型和业务影响。

PSI 能直接指出哪个进程最慢吗?

不能。PSI 描述资源争用造成的停顿,需要结合 cgroup、进程级观测、日志和业务指标继续归因。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>