云计算百科
云计算领域专业知识百科平台

Python系统监控利器:psutil详解

引言

psutil(Python system and process utilities)是一个跨平台的Python库,它允许开发人员轻松获取系统运行时的各种信息。这个库最初由Giampaolo Rodola在2009年创建,现在已经成为Python生态系统中系统监控领域的标准工具之一。psutil提供了一种简单而统一的方式来获取系统利用率信息(CPU、内存、磁盘、网络)和进程管理功能,不需要依赖系统特定的命令行工具。

在系统监控和资源管理领域,psutil扮演着至关重要的角色。它可以帮助开发人员:

  • 实时监控服务器资源使用情况
  • 诊断系统性能瓶颈
  • 自动管理进程生命周期
  • 构建自定义的系统监控工具
  • 实现自动化运维任务

安装与基本配置

安装方法

psutil可以通过Python的包管理工具pip轻松安装:

pip install psutil

对于特定版本的需求,可以指定版本号安装:

pip install psutil==5.9.0

兼容性说明

psutil具有出色的跨平台兼容性,支持以下操作系统:

  • Windows (32位和64位)
  • Linux (各主流发行版)
  • macOS
  • FreeBSD, OpenBSD, NetBSD
  • Sun Solaris
  • AIX

支持的Python版本包括:

  • Python 2.7 (psutil 5.x是最后一个支持Python 2的版本)
  • Python 3.4+
  • PyPy

核心功能与用法

获取系统信息

CPU使用率监控

psutil提供了多种CPU监控功能:

import psutil

# 获取CPU逻辑核心数
print(f"逻辑CPU核心数: {psutil.cpu_count()}")

# 获取CPU物理核心数(不包括超线程)
print(f"物理CPU核心数: {psutil.cpu_count(logical=False)}")

# 获取CPU使用率(阻塞1秒)
print(f"CPU使用率: {psutil.cpu_percent(interval=1)}%")

# 获取每个CPU核心的使用率
print(f"各核心使用率: {psutil.cpu_percent(interval=1, percpu=True)}")

# 获取CPU频率信息
cpu_freq = psutil.cpu_freq()
print(f"当前频率: {cpu_freq.current}MHz")
print(f"最小频率: {cpu_freq.min}MHz")
print(f"最大频率: {cpu_freq.max}MHz")

# 获取CPU统计信息(上下文切换、中断等)
print(f"CPU统计: {psutil.cpu_stats()}")

内存使用情况

psutil可以详细监控系统内存使用情况:

# 获取物理内存信息
mem = psutil.virtual_memory()
print(f"总内存: {mem.total/1024/1024:.2f} MB")
print(f"可用内存: {mem.available/1024/1024:.2f} MB")
print(f"已用内存: {mem.used/1024/1024:.2f} MB")
print(f"内存使用率: {mem.percent}%")

# 获取交换内存信息
swap = psutil.swap_memory()
print(f"交换内存总量: {swap.total/1024/1024:.2f} MB")
print(f"已用交换内存: {swap.used/1024/1024:.2f} MB")
print(f"交换内存使用率: {swap.percent}%")

磁盘I/O和分区信息

磁盘监控功能示例:

# 获取磁盘分区信息
partitions = psutil.disk_partitions()
for partition in partitions:
print(f"设备: {partition.device}")
print(f"挂载点: {partition.mountpoint}")
print(f"文件系统类型: {partition.fstype}")

# 获取磁盘使用情况
usage = psutil.disk_usage(partition.mountpoint)
print(f"总空间: {usage.total/1024/1024:.2f} MB")
print(f"已用空间: {usage.used/1024/1024:.2f} MB")
print(f"可用空间: {usage.free/1024/1024:.2f} MB")
print(f"使用率: {usage.percent}%")

# 获取磁盘IO统计
disk_io = psutil.disk_io_counters()
print(f"读取次数: {disk_io.read_count}")
print(f"写入次数: {disk_io.write_count}")
print(f"读取字节数: {disk_io.read_bytes/1024/1024:.2f} MB")
print(f"写入字节数: {disk_io.write_bytes/1024/1024:.2f} MB")

网络接口统计

网络监控功能:

# 获取网络接口信息
net_if = psutil.net_if_addrs()
for interface, addrs in net_if.items():
print(f"接口: {interface}")
for addr in addrs:
print(f" IP地址: {addr.address}")
print(f" 网络掩码: {addr.netmask}")
print(f" 广播地址: {addr.broadcast}")

# 获取网络IO统计
net_io = psutil.net_io_counters()
print(f"发送字节数: {net_io.bytes_sent/1024:.2f} KB")
print(f"接收字节数: {net_io.bytes_recv/1024:.2f} KB")
print(f"发送数据包数: {net_io.packets_sent}")
print(f"接收数据包数: {net_io.packets_recv}")

# 获取当前网络连接
connections = psutil.net_connections()
for conn in connections:
print(f"协议: {conn.type}")
print(f"本地地址: {conn.laddr}")
print(f"远程地址: {conn.raddr}")
print(f"状态: {conn.status}")

进程管理

列出当前运行的所有进程

# 获取所有进程ID
pids = psutil.pids()

# 遍历所有进程
for proc in psutil.process_iter(['pid', 'name', 'username']):
try:
# 获取进程详情
pinfo = proc.as_dict(attrs=['pid', 'name', 'cpu_percent', 'memory_percent'])
print(pinfo)
except psutil.NoSuchProcess:
pass

获取特定进程的详细信息

# 通过PID获取进程对象
pid = 1234 # 替换为实际PID
try:
p = psutil.Process(pid)

# 获取进程基本信息
print(f"进程名: {p.name()}")
print(f"执行路径: {p.exe()}")
print(f"工作目录: {p.cwd()}")
print(f"启动命令: {p.cmdline()}")
print(f"启动时间: {p.create_time()}")
print(f"用户名: {p.username()}")

# 获取资源使用情况
print(f"CPU使用率: {p.cpu_percent(interval=1.0)}%")
print(f"内存使用率: {p.memory_percent()}%")
mem_info = p.memory_info()
print(f"常驻内存: {mem_info.rss/1024/1024:.2f} MB")
print(f"虚拟内存: {mem_info.vms/1024/1024:.2f} MB")

# 获取线程信息
print(f"线程数: {p.num_threads()}")

# 获取打开的文件
print(f"打开的文件: {p.open_files()}")

# 获取网络连接
print(f"网络连接: {p.connections()}")

except psutil.NoSuchProcess:
print(f"进程 {pid} 不存在")

进程的启动、终止与管理

# 启动新进程
import subprocess
proc = subprocess.Popen(["python", "script.py"])
psutil_proc = psutil.Process(proc.pid)

# 终止进程
psutil_proc.terminate() # 优雅终止
psutil_proc.kill() # 强制终止

# 挂起和恢复进程
psutil_proc.suspend()
psutil_proc.resume()

# 等待进程结束
psutil_proc.wait(timeout=10)

系统性能优化与监控

实时监控系统资源

import time

def monitor_system(interval=1):
"""实时监控系统资源"""
while True:
# CPU使用率
cpu_percent = psutil.cpu_percent(interval=interval, percpu=True)

# 内存使用情况
mem = psutil.virtual_memory()

# 磁盘使用情况
disk = psutil.disk_usage('/')

# 网络IO
net_io = psutil.net_io_counters()

# 打印监控信息
print("\\n" + "="*50)
print(f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"CPU使用率: {cpu_percent}")
print(f"内存使用: {mem.percent}%")
print(f"磁盘使用: {disk.percent}%")
print(f"网络: 上传 {net_io.bytes_sent/1024:.2f}KB, 下载 {net_io.bytes_recv/1024:.2f}KB")

time.sleep(interval)

# monitor_system()

生成资源使用报告

def generate_report(duration=60, interval=5):
"""生成系统资源使用报告"""
records = []
end_time = time.time() + duration

while time.time() < end_time:
record = {
'timestamp': time.time(),
'cpu': psutil.cpu_percent(interval=interval),
'memory': psutil.virtual_memory().percent,
'disk': psutil.disk_usage('/').percent,
'network_sent': psutil.net_io_counters().bytes_sent,
'network_recv': psutil.net_io_counters().bytes_recv
}
records.append(record)

# 计算统计数据
cpu_avg = sum(r['cpu'] for r in records) / len(records)
mem_avg = sum(r['memory'] for r in records) / len(records)

report = {
'duration': duration,
'cpu_avg': cpu_avg,
'mem_avg': mem_avg,
'peak_cpu': max(r['cpu'] for r in records),
'peak_mem': max(r['memory'] for r in records),
'network_total': (records[-1]['network_sent'] – records[0]['network_sent'] +
records[-1]['network_recv'] – records[0]['network_recv']) / 1024
}

return report

# print(generate_report())

结合日志分析长期趋势

import logging
from logging.handlers import TimedRotatingFileHandler

def setup_monitoring_logger():
"""设置监控日志"""
logger = logging.getLogger('system_monitor')
logger.setLevel(logging.INFO)

# 每天轮换日志,保留7天
handler = TimedRotatingFileHandler(
'system_monitor.log',
when='D',
interval=1,
backupCount=7
)
formatter = logging.Formatter('%(asctime)s – %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)

return logger

def log_system_stats(logger, interval=300):
"""定期记录系统状态到日志"""
while True:
stats = {
'cpu': psutil.cpu_percent(interval=1),
'mem': psutil.virtual_memory().percent,
'disk': psutil.disk_usage('/').percent
}
logger.info(f"CPU: {stats['cpu']}% | MEM: {stats['mem']}% | DISK: {stats['disk']}%")
time.sleep(interval)

# logger = setup_monitoring_logger()
# log_system_stats(logger)

高级应用与技巧

多平台适配的注意事项

在使用psutil进行跨平台开发时,需要注意以下差异:

  • 路径表示:

    • Windows使用反斜杠(\\),而Unix-like系统使用正斜杠(/)
    • 建议使用os.path模块处理路径
  • 进程属性差异:

    def get_process_info(pid):
    try:
    p = psutil.Process(pid)
    info = {
    'pid': pid,
    'name': p.name(),
    'status': p.status(),
    'cpu': p.cpu_percent(interval=0.1),
    'memory': p.memory_info().rss
    }

    # Windows特有属性
    if hasattr(p, 'username'):
    info['user'] = p.username()

    # Unix特有属性
    if hasattr(p, 'terminal'):
    info['terminal'] = p.terminal()

    return info
    except psutil.NoSuchProcess:
    return None

  • 网络接口命名:

    • Windows: "以太网"、"Wi-Fi"
    • Linux: "eth0"、"wlan0"
    • macOS: "en0"、"en1"
  • 磁盘分区表示:

    • Windows: "C:"、"D:"
    • Unix-like: "/", "/home"
  • 结合其他工具进行数据可视化

    使用Pandas分析数据

    import pandas as pd

    def collect_system_data(samples=10, interval=1):
    """收集系统数据并返回DataFrame"""
    data = []
    for _ in range(samples):
    record = {
    'timestamp': pd.Timestamp.now(),
    'cpu': psutil.cpu_percent(interval=interval),
    'memory': psutil.virtual_memory().percent,
    'disk': psutil.disk_usage('/').percent
    }
    data.append(record)
    time.sleep(interval)

    return pd.DataFrame(data)

    # df = collect_system_data()
    # print(df.describe())

    使用Matplotlib绘制图表

    import matplotlib.pyplot as plt

    def plot_system_metrics(df):
    """绘制系统指标图表"""
    fig, axes = plt.subplots(nrows=3, ncols=1, figsize=(10, 8))

    # CPU使用率
    df.plot(x='timestamp', y='cpu', ax=axes[0], title='CPU Usage (%)', legend=False)
    axes[0].set_ylim(0, 100)

    # 内存使用率
    df.plot(x='timestamp', y='memory', ax=axes[1], title='Memory Usage (%)', legend=False)
    axes[1].set_ylim(0, 100)

    # 磁盘使用率
    df.plot(x='timestamp', y='disk', ax=axes[2], title='Disk Usage (%)', legend=False)
    axes[2].set_ylim(0, 100)

    plt.tight_layout()
    plt.show()

    # plot_system_metrics(df)

    异常处理与性能调优

    健壮的进程监控

    def safe_process_info(pid):
    """安全获取进程信息,处理各种异常"""
    try:
    p = psutil.Process(pid)
    return {
    'pid': pid,
    'name': p.name(),
    'status': p.status(),
    'cpu': p.cpu_percent(interval=0.1),
    'memory': p.memory_percent(),
    'threads': p.num_threads()
    }
    except psutil.NoSuchProcess:
    return {'error': 'Process not found'}
    except psutil.AccessDenied:
    return {'error': 'Access denied'}
    except psutil.ZombieProcess:
    return {'error': 'Zombie process'}
    except Exception as e:
    return {'error': str(e)}

    性能优化技巧
  • 批量获取属性:

    # 低效方式
    cpu = p.cpu_percent()
    mem = p.memory_percent()

    # 高效方式
    info = p.as_dict(attrs=['cpu_percent', 'memory_percent'])

  • 减少进程列表扫描频率:

    # 缓存进程列表
    cached_pids = set(psutil.pids())

    # 定期更新缓存
    if time.time() – last_update > 60:
    cached_pids = set(psutil.pids())
    last_update = time.time()

  • 使用with语句管理资源:

    with psutil.Process(pid) as p:
    print(p.name())
    print(p.status())

  • 实际案例

    服务器监控脚本的实现

    #!/usr/bin/env python3
    """
    服务器资源监控脚本
    监控CPU、内存、磁盘、网络使用情况
    当资源超过阈值时发送告警
    """

    import psutil
    import time
    import smtplib
    from email.mime.text import MIMEText

    # 配置参数
    THRESHOLDS = {
    'cpu': 90, # CPU使用率阈值(%)
    'memory': 90, # 内存使用率阈值(%)
    'disk': 90, # 磁盘使用率阈值(%)
    }

    ALERT_INTERVAL = 3600 # 告警间隔(秒)
    MONITOR_INTERVAL = 5 # 监控间隔(秒)

    # 邮件配置
    SMTP_SERVER = 'smtp.example.com'
    SMTP_PORT = 587
    EMAIL_USER = 'monitor@example.com'
    EMAIL_PASS = 'password'
    EMAIL_TO = 'admin@example.com'

    last_alert_time = 0

    def check_thresholds():
    """检查各项指标是否超过阈值"""
    alerts = []

    # CPU检查
    cpu_percent = psutil.cpu_percent(interval=1)
    if cpu_percent > THRESHOLDS['cpu']:
    alerts.append(f"CPU使用率过高: {cpu_percent}%")

    # 内存检查
    mem_percent = psutil.virtual_memory().percent
    if mem_percent > THRESHOLDS['memory']:
    alerts.append(f"内存使用率过高: {mem_percent}%")

    # 磁盘检查
    disk_percent = psutil.disk_usage('/').percent
    if disk_percent > THRESHOLDS['disk']:
    alerts.append(f"磁盘使用率过高: {disk_percent}%")

    return alerts

    def send_alert(alerts):
    """发送告警邮件"""
    global last_alert_time

    current_time = time.time()
    if current_time – last_alert_time < ALERT_INTERVAL:
    return

    subject = "服务器资源告警"
    body = "\\n".join(alerts)

    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = EMAIL_USER
    msg['To'] = EMAIL_TO

    try:
    with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
    server.starttls()
    server.login(EMAIL_USER, EMAIL_PASS)
    server.send_message(msg)
    last_alert_time = current_time
    print(f"告警已发送: {alerts}")
    except Exception as e:
    print(f"发送告警失败: {e}")

    def main():
    """主监控循环"""
    print("启动服务器监控…")
    while True:
    alerts = check_thresholds()
    if alerts:
    send_alert(alerts)
    time.sleep(MONITOR_INTERVAL)

    if __name__ == '__main__':
    main()

    自动化运维任务示例

    #!/usr/bin/env python3
    """
    自动化运维脚本
    1. 监控指定进程,如果崩溃则自动重启
    2. 清理过期的日志文件
    3. 定期备份重要数据
    """

    import psutil
    import os
    import time
    import shutil
    import subprocess
    from datetime import datetime, timedelta

    # 配置参数
    PROCESS_NAME = "my_service" # 要监控的进程名
    PROCESS_CMD = ["python", "service.py"] # 进程启动命令
    LOG_DIR = "/var/log/myapp" # 日志目录
    BACKUP_DIR = "/backups" # 备份目录
    DATA_DIR = "/data" # 要备份的数据目录
    RETENTION_DAYS = 7 # 日志和备份保留天数
    CHECK_INTERVAL = 60 # 检查间隔(秒)

    def find_process():
    """查找指定进程"""
    for proc in psutil.process_iter(['name', 'cmdline']):
    try:
    if proc.info['name'] == PROCESS_NAME or \\
    (proc.info['cmdline'] and proc.info['cmdline'][0] == PROCESS_CMD[0]):
    return proc
    except (psutil.NoSuchProcess, psutil.AccessDenied):
    continue
    return None

    def start_process():
    """启动进程"""
    print(f"启动进程: {' '.join(PROCESS_CMD)}")
    subprocess.Popen(PROCESS_CMD)

    def cleanup_files(directory, pattern, days):
    """清理过期文件"""
    now = datetime.now()
    cutoff = now – timedelta(days=days)

    for filename in os.listdir(directory):
    if filename.endswith(pattern):
    filepath = os.path.join(directory, filename)
    mtime = datetime.fromtimestamp(os.path.getmtime(filepath))
    if mtime < cutoff:
    print(f"删除过期文件: {filepath}")
    os.remove(filepath)

    def create_backup():
    """创建数据备份"""
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    backup_name = f"backup_{timestamp}.tar.gz"
    backup_path = os.path.join(BACKUP_DIR, backup_name)

    print(f"创建备份: {backup_path}")
    shutil.make_archive(backup_path.replace('.tar.gz', ''), 'gztar', DATA_DIR)
    return backup_path

    def main():
    """主循环"""
    print("启动自动化运维脚本…")

    while True:
    # 检查进程
    proc = find_process()
    if proc is None:
    print("进程未运行,尝试启动…")
    start_process()
    else:
    print(f"进程运行中,PID: {proc.pid}")

    # 清理过期日志
    print("清理过期日志…")
    cleanup_files(LOG_DIR, ".log", RETENTION_DAYS)

    # 创建定期备份
    if datetime.now().hour == 2: # 每天凌晨2点备份
    print("执行每日备份…")
    create_backup()
    print("清理过期备份…")
    cleanup_files(BACKUP_DIR, ".tar.gz", RETENTION_DAYS)

    time.sleep(CHECK_INTERVAL)

    if __name__ == '__main__':
    main()

    常见问题与解决方案

    常见错误与调试方法

  • NoSuchProcess错误:

    • 问题:尝试访问已终止的进程时抛出
    • 解决方案:

      try:
      p = psutil.Process(pid)
      print(p.name())
      except psutil.NoSuchProcess:
      print(f"进程 {pid} 已终止")

  • AccessDenied错误:

    • 问题:权限不足访问某些进程信息
    • 解决方案:
      • Linux/Mac: 使用sudo运行脚本
      • Windows: 以管理员身份运行
      • 或者捕获异常处理:

        try:
        p = psutil.Process(pid)
        print(p.environ())
        except psutil.AccessDenied:
        print("权限不足,无法访问进程环境")

  • ZombieProcess错误:

    • 问题:进程处于僵尸状态
    • 解决方案:

      try:
      p = psutil.Process(pid)
      if p.status() == psutil.STATUS_ZOMBIE:
      print("进程处于僵尸状态")
      except psutil.ZombieProcess:
      print("无法访问僵尸进程")

  • 性能问题:

    • 问题:频繁获取进程列表导致性能下降
    • 解决方案:
      • 减少扫描频率
      • 缓存进程列表
      • 使用pids()代替process_iter()获取特定PID
  • 性能瓶颈分析

  • 识别高CPU进程:

    def find_top_cpu_processes(n=5):
    """查找CPU占用最高的n个进程"""
    procs = []
    for p in psutil.process_iter(['pid', 'name', 'cpu_percent']):
    try:
    p.info['cpu_percent'] = p.info['cpu_percent'] or 0
    procs.append(p.info)
    except (psutil.NoSuchProcess, psutil.AccessDenied):
    continue

    # 按CPU使用率排序
    return sorted(procs, key=lambda x: x['cpu_percent'], reverse=True)[:n]

  • 识别内存泄漏:

    def monitor_memory_leak(pid, interval=60, threshold=10):
    """监控内存泄漏"""
    baseline = None
    while True:
    try:
    p = psutil.Process(pid)
    mem = p.memory_info().rss / 1024 / 1024 # MB

    if baseline is None:
    baseline = mem
    print(f"初始内存: {baseline:.2f} MB")
    else:
    increase = mem – baseline
    if increase > threshold:
    print(f"警告: 内存增加了 {increase:.2f} MB (当前: {mem:.2f} MB)")

    time.sleep(interval)
    except psutil.NoSuchProcess:
    print("进程已终止")
    break

  • 磁盘IO瓶颈分析:

    def analyze_disk_io():
    """分析磁盘IO瓶颈"""
    # 获取磁盘IO统计
    disk_io = psutil.disk_io_counters()
    print(f"读取次数: {disk_io.read_count}")
    print(f"写入次数: {disk_io.write_count}")

    # 查找高IO进程
    high_io_procs = []
    for p in psutil.process_iter(['pid', 'name', 'io_counters']):
    try:
    io = p.info['io_counters']
    if io and (io.read_bytes > 100*1024*1024 or io.write_bytes > 100*1024*1024): # 100MB
    high_io_procs.append({
    'pid': p.info['pid'],
    'name': p.info['name'],
    'read': io.read_bytes / 1024 / 1024,
    'write': io.write_bytes / 1024 / 1024
    })
    except (psutil.NoSuchProcess, psutil.AccessDenied):
    continue

    return high_io_procs

  • 总结

    psutil的优势与适用场景

    psutil作为Python系统监控的标准库,具有以下显著优势:

  • 跨平台支持:统一的API在不同的操作系统上工作
  • 功能全面:覆盖CPU、内存、磁盘、网络、进程等各个方面
  • 简单易用:直观的API设计,学习曲线平缓
  • 性能高效:底层使用C扩展实现,资源消耗低
  • 活跃维护:持续更新,支持最新的Python版本和操作系统
  • psutil非常适合以下场景:

    • 服务器监控和告警系统
    • 自动化运维工具开发
    • 系统性能分析和调优
    • 资源使用统计和报告生成
    • 进程管理和监控工具

    未来发展方向与社区支持

    psutil项目持续活跃发展,未来可能的方向包括:

  • 更丰富的容器支持:增强对Docker、Kubernetes等容器环境的监控
  • GPU监控:增加对GPU使用情况的监控功能
  • 更详细的进程分析:提供更深层次的进程剖析功能
  • 异步API支持:适应现代异步编程范式
  • psutil拥有一个活跃的开源社区,用户可以通过以下方式获取支持和参与贡献:

    • GitHub仓库: https://github.com/giampaolo/psutil
    • 官方文档: https://psutil.readthedocs.io/
    • 邮件列表和问题追踪

    通过psutil,Python开发者可以轻松构建强大的系统监控和管理工具,极大地简化了与系统资源交互的复杂性,是每个系统管理员和DevOps工程师工具箱中不可或缺的利器。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Python系统监控利器:psutil详解
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!