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/自研采集器需求)
- 主机指标采集:CPU、内存、磁盘、网络、温度、开机时间
- 进程管理:遍历进程、杀进程、获取进程CPU/内存/文件句柄/线程数
- 容器简易监控、自定义监控Agent、时序指标上报
- 脚本资源限制:检测脚本自身内存占用、防止OOM
- 堡垒机/备份脚本前置校验磁盘空间
- 本地轻量异常检测(CPU持续100%、内存占用过高自动告警)
1.3. 跨平台特性
完全兼容:Linux / Windows / macOS / FreeBSD;API 统一,不用区分系统写两套逻辑。
1.4. 安装
pip install psutil
2. 整体模块划分
psutil 分为五大核心功能模块:
- CPU 相关:cpu_count / cpu_percent / cpu_times / cpu_stats
- 内存相关:virtual_memory / swap_memory
- 磁盘相关:disk_partitions / disk_usage / disk_io_counters
- 网络相关:net_io_counters / net_connections / net_if_addrs
- 进程相关:Process、pids()、process_iter()、kill进程
- 系统辅助: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 调用系统命令对比
| 维度 | psutil | subprocess调用top/df/free |
| 输出格式 | 结构化数字字典,无需文本解析 | 纯文本,必须split/strip正则提取数值,极易出错 |
| 性能 | 直接系统调用,开销极低 | 创建子进程、管道读写,大量采集CPU开销高 |
| 跨平台 | 一套代码统一API | Windows/Linux命令完全不同,需要分支判断 |
| 异常处理 | 专属精准异常类 | 只能判断返回码,解析文本报错模糊 |
| 适用场景 | 自研监控采集、AIOps指标Agent、定时巡检 | 一次性临时查看,不适合持续自动化采集 |
19. 结合你自研AIOps产品的价值
- 作为自研采集器核心底层,替代各类exporter,轻量采集主机指标;
- 内置进程监控,实现进程OOM、高CPU自动识别自愈;
- 备份脚本前置磁盘校验,保障备份可靠性;
- 实时获取TCP连接数,检测端口异常连接、端口扫描;
- 无需依赖Prometheus生态,轻量化本地监控方案,适配轻量云主机2核4G环境。
关联文档