You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS EC2上如何监控Python脚本的已打开文件与磁盘带宽?

针对你在AWS EC2 Ubuntu 18.04上遇到的Python脚本磁盘读带宽过高、耗尽EBS burst_balance导致系统不稳定的问题,我整理了几个实用的定位工具和方法,帮你精准找到带宽消耗的源头:

一、系统级命令工具(快速定位进程与文件)

这些工具不需要修改Python代码,直接在终端运行就能快速排查:

  • iostat:先确认整体磁盘的读负载情况,运行命令:

    iostat -x 5
    

    -x显示扩展统计信息,5表示每5秒刷新一次。重点看rMB/s列,这就是每秒磁盘读取的MB数,先确认峰值是否和你观察到的130MiB/s匹配。

  • iotop:实时查看进程级的IO占用,直接运行:

    iotop
    

    界面会显示每个进程的DISK READ速率,按大写O可以按IO使用率排序,快速找到占用读带宽最高的Python进程。记下对应的PID,后续可以进一步分析它的文件操作。

  • lsof:查看目标进程打开的所有文件,比如你找到的Python进程PID是1234,运行:

    lsof -p 1234 | grep REG
    

    REG类型代表普通磁盘文件,这样就能列出该进程正在读写的所有文件,结合iotop的带宽数据,就能初步锁定可疑文件。

  • pidstat:针对特定进程做持续IO统计,比如监控PID为1234的进程:

    pidstat -d 5 -p 1234
    

    -d表示聚焦IO统计,5秒刷新一次,能看到该进程的实时读带宽(kB_rd/s列,转成MB的话除以1024),方便观察带宽变化趋势。

二、Python代码级监控(精准追踪文件读取)

如果想从脚本内部或单独监控脚本的文件读写行为,可以用这些方法:

  • psutil库:这是一个强大的跨平台系统监控库,能获取进程的IO统计和打开的文件列表。先安装:

    pip install psutil
    

    可以写一个简单的监控脚本,或者嵌入到你的主程序中:

    import psutil
    import time
    
    # 监控当前Python进程(如果监控其他进程,替换成目标PID)
    target_pid = psutil.Process().pid
    prev_read_bytes = psutil.Process(target_pid).io_counters().read_bytes
    
    while True:
        time.sleep(1)
        curr_read_bytes = psutil.Process(target_pid).io_counters().read_bytes
        read_speed_mb = (curr_read_bytes - prev_read_bytes) / 1024 / 1024
        print(f"当前读带宽: {read_speed_mb:.2f} MB/s")
        
        print("已打开的文件:")
        for file in psutil.Process(target_pid).open_files():
            print(f"  {file.path}")
        
        prev_read_bytes = curr_read_bytes
    

    这个脚本会实时输出读带宽和当前打开的文件,帮你关联文件与带宽消耗。

  • 自定义文件读取追踪器:如果想精准统计每个文件的总读取量,可以包装Python的open函数,记录每个文件的读取字节数:

    import builtins
    import os
    import time
    
    # 存储每个文件的读取字节数
    file_read_stats = {}
    original_open = builtins.open
    
    def tracked_open(path, *args, **kwargs):
        file_obj = original_open(path, *args, **kwargs)
        # 只跟踪读模式的文件
        mode = args[0] if args else kwargs.get('mode', 'r')
        if 'r' in mode:
            abs_path = os.path.abspath(path)
            file_read_stats[abs_path] = file_read_stats.get(abs_path, 0)
            
            # 包装read方法
            original_read = file_obj.read
            def tracked_read(size=-1):
                data = original_read(size)
                file_read_stats[abs_path] += len(data)
                return data
            file_obj.read = tracked_read
            
            # 同理包装readline、readlines等方法(如果需要)
            original_readline = file_obj.readline
            def tracked_readline():
                line = original_readline()
                file_read_stats[abs_path] += len(line)
                return line
            file_obj.readline = tracked_readline
        
        return file_obj
    
    # 替换系统open函数
    builtins.open = tracked_open
    
    # ----------------------
    # 这里运行你的主脚本代码
    # ----------------------
    
    # 定期打印统计结果
    while True:
        print("\n文件读取统计(MB):")
        # 按读取量从大到小排序
        for path, bytes_read in sorted(file_read_stats.items(), key=lambda x: -x[1]):
            print(f"  {path}: {bytes_read / 1024 / 1024:.2f} MB")
        time.sleep(5)
    

    这个方法能精准定位哪些文件被读取了大量数据,尤其是你提到的200个小文件,如果被反复读取,这里会清晰显示出来。

三、额外排查思路
  • 区分缓存读取与实际磁盘IO:Ubuntu会用空闲内存做文件缓存,有时候看似高读带宽,其实是从缓存读取,不会消耗EBS的burst_balance。可以用vmstat 5查看bi列(单位KB),bi*1024就是每秒实际从磁盘读入的字节数,这个才是真正影响burst_balance的数值。
  • 检查重复读取逻辑:你提到的200个小文件总容量最多60MB,持续半小时130MiB/s的读速率显然是重复读取导致的。用上面的工具找到被频繁读取的文件,再检查脚本中是否有循环读取、重复加载的逻辑。
  • EBS卷类型优化:如果最终确认是业务需要持续高读IO,考虑将gp2卷换成gp3卷,gp3的burst性能更稳定,不会轻易耗尽burst_balance。

内容的提问来源于stack exchange,提问作者draufunddran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:33:09