Python

psutil 系统监控详解

·20 分钟阅读·7743 字

psutil 系统监控详解 的详细笔记

📋 目录

psutil 系统监控详解

核心概念 psutil 是 Python 系统和进程监控库,跨平台获取 CPU/内存/磁盘/网络信息。

1. 基础概述

1.1. 定义

psutil = process + utility,跨平台系统资源监控库,纯Python封装,底层调用系统C接口(Linux /proc、Windows API、macOS libproc),替代系统命令(ps、top、df、free、netstat、lsof),无需调用subprocess、无需解析文本输出,直接拿到结构化数值。

1.2. 核心适用场景(贴合你的AIOps/自研采集器需求)

  1. 主机指标采集:CPU、内存、磁盘、网络、温度、开机时间
  2. 进程管理:遍历进程、杀进程、获取进程CPU/内存/文件句柄/线程数
  3. 容器简易监控、自定义监控Agent、时序指标上报
  4. 脚本资源限制:检测脚本自身内存占用、防止OOM
  5. 堡垒机/备份脚本前置校验磁盘空间
  6. 本地轻量异常检测(CPU持续100%、内存占用过高自动告警)

1.3. 跨平台特性

完全兼容:Linux / Windows / macOS / FreeBSD;API 统一,不用区分系统写两套逻辑。

1.4. 安装

pip install psutil

2. 整体模块划分

psutil 分为五大核心功能模块:

  1. CPU 相关:cpu_count / cpu_percent / cpu_times / cpu_stats
  2. 内存相关:virtual_memory / swap_memory
  3. 磁盘相关:disk_partitions / disk_usage / disk_io_counters
  4. 网络相关:net_io_counters / net_connections / net_if_addrs
  5. 进程相关:Process、pids()、process_iter()、kill进程
  6. 系统辅助:boot_time、users、sensors(温度/风扇)

三、分模块完整API详解 + 运维实战示例

3. 模块1:CPU 信息采集

3.1. psutil.cpu_count(logical=True)

获取CPU核心数

  • logical=True:逻辑核心(超线程,top看到的核心)
  • logical=False:物理核心
import psutil
print(psutil.cpu_count())        # 逻辑核总数
print(psutil.cpu_count(False))   # 物理核

3.2. psutil.cpu_percent(interval=None, percpu=False) CPU使用率

  • interval=1:采样1秒计算精准使用率;interval=None 返回瞬时值(误差大)
  • percpu=True 返回每个核心单独使用率列表
# 整体CPU使用率,采样1秒
total_cpu = psutil.cpu_percent(interval=1)
# 每核使用率
per_core = psutil.cpu_percent(interval=1, percpu=True)
print("整机CPU:", total_cpu)
print("各核心占用:", per_core)

3.3. psutil.cpu_times() / cpu_times_percent()

区分 us(用户态)、sy(内核态)、idle空闲、iowait等待IO,对应top命令us/sy/wa指标

times = psutil.cpu_times()
print("用户态耗时", times.user)
print("内核态耗时", times.system)
print("IO等待", times.iowait)

3.4. psutil.cpu_stats()

软中断、硬中断、上下文切换次数,排查内核高开销场景

stats = psutil.cpu_stats()
print("上下文切换次数:", stats.ctx_switches)
print("硬中断:", stats.interrupts)
print("软中断:", stats.soft_interrupts)

4. 模块2:内存信息(virtual_memory 物理内存、swap交换分区)

4.1. psutil.virtual_memory() 物理内存

返回命名元组,所有单位字节,需要手动换算MB/GB
字段说明:

  • total:总内存
  • available:可用内存(包含缓存、buffers,系统可快速回收)
  • used:已使用内存
  • free:纯空闲内存
  • buffers / cached:页缓存、缓冲区
  • percent:内存占用百分比(最常用)
mem = psutil.virtual_memory()
GB = 1024 ** 3
print(f"总内存:{mem.total / GB:.2f}G")
print(f"可用内存:{mem.available / GB:.2f}G")
print(f"内存使用率:{mem.percent}%")

4.2. psutil.swap_memory() 交换分区swap

swap = psutil.swap_memory()
print(f"swap总大小:{swap.total/GB:.2f}G,已使用{swap.percent}%")

5. 模块3:磁盘存储

5.1. psutil.disk_partitions(all=False) 获取所有挂载分区

过滤真实磁盘,排除tmpfs、sysfs虚拟文件系统(all=False)
返回每个分区设备名、挂载点、文件系统类型(fstype)

parts = psutil.disk_partitions()
for p in parts:
    print("设备", p.device, "挂载点", p.mountpoint, "文件系统", p.fstype)

5.2. psutil.disk_usage(path) 获取挂载点磁盘使用(备份脚本必备)

输入挂载路径,返回总大小、已用、可用、占用百分比,用于前置校验磁盘空间是否足够备份

disk = psutil.disk_usage("/")
GB = 1024**3
print(f"/ 总容量 {disk.total/GB:.1f}G,可用 {disk.free/GB:.1f}G,使用率 {disk.percent}%")
# 生产判断:磁盘占用超过90%告警
if disk.percent > 90:
    print("磁盘空间不足告警")

5.3. psutil.disk_io_counters(perdisk=False) 磁盘IO读写统计

整机/单块磁盘读写字节、IO次数,排查磁盘IO瓶颈

disk_io = psutil.disk_io_counters()
print("累计读字节", disk_io.read_bytes)
print("累计写字节", disk_io.write_bytes)
# perdisk=True 返回每块磁盘单独数据
per_disk_io = psutil.disk_io_counters(perdisk=True)

6. 模块4:网络指标(替代netstat、ss、cat /proc/net/dev)

6.1. psutil.net_io_counters(pernic=False) 网卡流量统计

整机/单网卡收发字节、数据包、丢包

net = psutil.net_io_counters()
print("总接收字节", net.bytes_recv)
print("总发送字节", net.bytes_sent)
# 单网卡
per_net = psutil.net_io_counters(pernic=True)
print(per_net["eth0"])

6.2. psutil.net_connections(kind=“inet”) 获取所有TCP/UDP连接

等价 ss -ant,返回本地端口、远端IP、连接状态(ESTABLISHED/LISTEN/TIME_WAIT),端口巡检、异常连接检测

# kind 可选 inet(tcp+udp), tcp, udp
conns = psutil.net_connections(kind="tcp")
for c in conns:
    laddr = c.laddr  # (ip, port)
    raddr = c.raddr  # 远端地址
    status = c.status
    print("本地端口", laddr.port, "状态", status)

6.3. psutil.net_if_addrs() 获取网卡IP地址

ifs = psutil.net_if_addrs()
for name, addrs in ifs.items():
    for addr in addrs:
        print(f"网卡{name} IP:{addr.address}")

7. 模块5:进程管理(核心高频功能,运维脚本大量使用)

7.1. 获取所有进程PID列表

all_pids = psutil.pids()
print("当前进程总数:", len(all_pids))

7.2. psutil.Process(pid) 进程对象,单个进程完整信息

传入PID创建进程实例,可读取CPU、内存、线程、打开文件、命令行、用户、句柄等

7.2.1. 常用属性与方法

pid = 1234
p = psutil.Process(pid)

# 基础信息
print("进程PID", p.pid)
print("进程名称", p.name())
print("启动命令行", p.cmdline())  # ["/usr/bin/python3", "agent.py"]
print("进程用户", p.username())
print("创建时间", p.create_time())

# 资源占用
print("进程CPU占用", p.cpu_percent(interval=0.1))
mem_info = p.memory_info()
print("进程RSS物理内存字节", mem_info.rss)
print("虚拟内存vms", mem_info.vms)

# 打开文件句柄(排查too many open files)
open_files = p.open_files()
print("进程打开文件数", len(open_files))

# 线程数量
threads = p.threads()
print("线程数", len(threads))

# 终止进程
# p.terminate() 优雅 SIGTERM
# p.kill() 强制 SIGKILL
# p.wait() 等待进程回收,防止僵尸进程

7.3. process_iter() 迭代遍历所有进程(比pids+Process更高效)

适合批量筛选进程,比如查找nginx、mysql进程

# 筛选所有python进程
for proc in psutil.process_iter(["pid", "name", "cmdline"]):
    try:
        info = proc.info
        if info["name"] and "python" in info["name"]:
            print("PID", info["pid"], info["cmdline"])
    except psutil.NoSuchProcess:
        # 遍历过程中进程已退出,直接跳过
        continue

7.4. 进程专属异常

  • psutil.NoSuchProcess:PID不存在,进程已退出
  • psutil.AccessDenied:无权限读取进程信息(非root读取root进程)

8. 模块6:系统辅助工具函数

8.1. psutil.boot_time() 系统开机时间

返回时间戳,可计算运行天数

import time
boot_ts = psutil.boot_time()
run_seconds = time.time() - boot_ts
print(f"系统已运行 {run_seconds / 86400:.1f} 天")

8.2. psutil.users() 当前登录用户

users = psutil.users()
for u in users:
    print("登录用户", u.name, "终端", u.terminal)

8.3. psutil.sensors_temperatures() Linux硬件温度(服务器监控)

读取CPU、硬盘温度,部分服务器支持

temp = psutil.sensors_temperatures()
for chip, entries in temp.items():
    for entry in entries:
        print(f"{chip} {entry.label}: {entry.current} ℃")

四、生产常用封装示例(适配你的AIOps采集器)

9. 示例1:一键采集整机核心指标,返回字典上报Prometheus

import psutil
import time

GB = 1024 ** 3

def get_host_metrics():
    # CPU
    cpu_total = psutil.cpu_percent(interval=0.8)
    cpu_core_num = psutil.cpu_count()
    # 内存
    mem = psutil.virtual_memory()
    mem_total_gb = round(mem.total / GB, 2)
    mem_used_gb = round((mem.total - mem.available) / GB, 2)
    mem_used_pct = mem.percent
    # 根磁盘
    root_disk = psutil.disk_usage("/")
    disk_root_pct = root_disk.percent
    # 开机时长
    uptime = round((time.time() - psutil.boot_time()) / 86400, 1)

    return {
        "cpu_percent": cpu_total,
        "cpu_core": cpu_core_num,
        "mem_total_gb": mem_total_gb,
        "mem_used_gb": mem_used_gb,
        "mem_percent": mem_used_pct,
        "root_disk_percent": disk_root_pct,
        "uptime_day": uptime
    }

print(get_host_metrics())

10. 示例2:备份脚本前置磁盘空间校验

def check_disk_enough(path, need_gb):
    """检查挂载点可用空间是否大于指定GB"""
    disk = psutil.disk_usage(path)
    free_gb = disk.free / (1024**3)
    return free_gb >= need_gb

# 备份至少需要5GB空间
if not check_disk_enough("/data/backup", 5):
    raise Exception("备份磁盘剩余空间不足,终止备份")

11. 示例3:批量杀死占用内存过高的异常进程(简易自愈逻辑)

def kill_high_mem_process(threshold_pct=80):
    for proc in psutil.process_iter(["pid", "name", "memory_percent"]):
        try:
            info = proc.info
            mem_pct = info["memory_percent"]
            pid = info["pid"]
            name = info["name"]
            if mem_pct >= threshold_pct:
                print(f"高内存进程 {name} pid={pid} 占用{mem_pct}%,执行终止")
                p = psutil.Process(pid)
                p.terminate()
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue

五、高频坑点与生产注意事项

12. cpu_percent(interval=None) 数值不准

必须传 interval=0.5/1,函数会阻塞采样一段时间计算真实使用率;不传interval只返回瞬时快照,波动极大。

13. 遍历进程时报 NoSuchProcess

迭代时进程瞬间退出,捕获该异常直接continue跳过,不可中断采集流程。

14. 非root权限限制

普通用户无法读取root进程的cmdline、内存、文件句柄,会抛出AccessDenied;采集Agent建议以root运行。

15. 所有磁盘/内存单位都是字节,必须手动换算GB

1GB = 1024**3,不要直接除以1000。

16. 频繁创建Process对象性能损耗

大批量遍历进程优先使用 process_iter(attrs=[...]),一次性预加载所需字段,减少系统调用。

17. 长期循环采集注意资源释放

psutil无句柄泄露问题,但不要无限循环不睡眠,建议采集间隔10~30秒,降低系统开销。

18. Windows特殊差异

Windows无iowait、无sensors温度、进程权限模型不同,API名称统一但部分字段为空。


六、psutil vs subprocess 调用系统命令对比

维度psutilsubprocess调用top/df/free
输出格式结构化数字字典,无需文本解析纯文本,必须split/strip正则提取数值,极易出错
性能直接系统调用,开销极低创建子进程、管道读写,大量采集CPU开销高
跨平台一套代码统一APIWindows/Linux命令完全不同,需要分支判断
异常处理专属精准异常类只能判断返回码,解析文本报错模糊
适用场景自研监控采集、AIOps指标Agent、定时巡检一次性临时查看,不适合持续自动化采集

19. 结合你自研AIOps产品的价值

  1. 作为自研采集器核心底层,替代各类exporter,轻量采集主机指标;
  2. 内置进程监控,实现进程OOM、高CPU自动识别自愈;
  3. 备份脚本前置磁盘校验,保障备份可靠性;
  4. 实时获取TCP连接数,检测端口异常连接、端口扫描;
  5. 无需依赖Prometheus生态,轻量化本地监控方案,适配轻量云主机2核4G环境。

关联文档

Yanche Blog

记录云原生、Linux、数据库等技术领域的学习心得,以及日常生活的思考与感悟。

© 2026 Yanche Blog. All rights reserved.

Powered by Astro