使用django-bakery执行gzip时报No space on device错误问题咨询
问题解答
问题1:为什么报错出现在写入磁盘步骤,而非写入内存缓冲区步骤
- Python的
BytesIO写入时如果触发内存不足,会抛出明确的MemoryError,你遇到的OSError 28本质是操作系统文件系统操作返回的错误码被误读为磁盘空间不足。 - 你的build目录存在1600万+文件,新建文件时操作系统需要为新文件分配目录项(dentry)、inode内核缓存,而此时你的物理内存已经被批量并行生成的大量gzip内存缓冲区占满,内核无法分配元数据操作所需的内存,就会返回
ENOSPC错误码,被上层fs库直接识别为磁盘空间不足。 - 写入内存缓冲区时内存刚好满足最低分配要求,执行
open操作时需要额外申请内核资源,此时才触发资源不足错误,因此报错位置出现在写磁盘步骤。
问题2:更优解决方案
不需要重写底层代码,可按优先级选择以下方案:
- 最便捷方案:构建前先清空历史build目录,1600万+旧文件的目录项缓存本身会占用大量内存,清空后重新构建可直接消除元数据操作的内存压力。
- 无代码修改方案:调整django-bakery的构建参数,关闭并行构建改为串行执行,同一时间仅会保留1份gzip内存缓冲区,处理完成后自动释放,不会出现内存累积占满的问题。
- 系统配置方案:扩容swap分区到8~16G,swap本身就是操作系统层面的「内存不足自动落盘」机制,开启后不常用的内存缓冲区会自动换出到磁盘,不会直接抛出资源不足错误。
- 轻量代码修改方案:通过monkey patch替换django-bakery的
gzip_file方法,直接将GzipFile的输出绑定到文件对象,无需经过内存缓冲区中转,压缩过程仅保留几十KB的滑动窗口内存占用,可将内存消耗降到最低。
补充说明:Python标准库的gzip模块本身没有自动切换磁盘的内置配置,内存分配策略由操作系统统一管理,配置swap即可实现你需要的内存不足自动使用磁盘缓存的效果。
内容的提问来源于stack exchange,提问作者Cerin
相关产品推荐
相关产品推荐

