共计 2508 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点
最近在用 Autodl 跑深度学习训练时,突然收到 ”No space left on device” 的报错,发现 200GB 的数据盘居然被塞满了。手动清理时又遇到各种坑:

- 直接
rm -rf报Device or resource busy,不知道哪个进程在占用文件 - 误删了还没备份的 checkpoint 文件
- 清理后没多久空间又爆满,需要反复人工介入
技术方案
第一步:定位占用进程
遇到文件删不掉时,先用这两个工具查凶手:
# 查看正在使用指定文件的进程
lsof +D /path/to/directory
# 更直接的方式(推荐)fuser -vm /path/to/mount_point
会显示类似这样的输出:
USER PID ACCESS COMMAND
/mnt/data: user1 12345 ..c.. python
user2 67890 F.... jupyter-lab
第二步:安全卸载文件系统
确认无重要进程后,标准卸载流程:
# 正常卸载(推荐首选)sudo umount /mnt/data
# 遇到顽固占用时(慎用)sudo umount -l /mnt/data # lazy 卸载
# 终极手段(可能损坏数据)sudo umount -f /mnt/data # 强制卸载
第三步:自动化清理脚本
新建cleaner.py(记得 chmod +x):
#!/usr/bin/env python3
import os
import time
import logging
from datetime import datetime, timedelta
# 配置区域 ===========================
TARGET_DIR = "/mnt/data/temp" # 监控目录
THRESHOLD = 80 # 磁盘使用百分比阈值
MAX_AGE_DAYS = 7 # 文件最大保留天数
LOG_FILE = "/var/log/cleaner.log" # 日志路径
# ===================================
def setup_logging():
logging.basicConfig(
filename=LOG_FILE,
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def check_disk_usage():
stat = os.statvfs(TARGET_DIR)
used_percent = 100 - (stat.f_bavail * 100 / stat.f_blocks)
return used_percent
def should_delete(filepath):
# 跳过隐藏文件和当前目录
if os.path.basename(filepath).startswith('.'):
return False
# 检查文件年龄
file_mtime = datetime.fromtimestamp(os.path.getmtime(filepath))
return (datetime.now() - file_mtime) > timedelta(days=MAX_AGE_DAYS)
def safe_remove(filepath):
try:
if os.path.isfile(filepath):
os.remove(filepath)
logging.info(f"Deleted file: {filepath}")
elif os.path.isdir(filepath):
os.rmdir(filepath) # 确保目录为空
logging.info(f"Deleted dir: {filepath}")
except Exception as e:
logging.error(f"Failed to delete {filepath}: {str(e)}")
if __name__ == "__main__":
setup_logging()
if check_disk_usage() > THRESHOLD:
logging.warning("Disk space over threshold! Starting cleanup...")
for root, dirs, files in os.walk(TARGET_DIR, topdown=False):
[safe_remove(os.path.join(root, f)) for f in files if should_delete(os.path.join(root, f))]
[safe_remove(os.path.join(root, d)) for d in dirs if should_delete(os.path.join(root, d))]
logging.info(f"Cleanup completed. Current usage: {check_disk_usage():.1f}%")
避坑指南
模型 checkpoint 保护
- 给重要文件添加
.keep后缀 - 使用专用目录存放(如
/mnt/data/checkpoints) - 在脚本中添加白名单逻辑:
WHITELIST = ['model.pt', 'checkpoint']
def should_delete(filepath):
return not any(w in filepath for w in WHITELIST)
处理 Docker 占用
常见报错:rm: cannot remove 'file': Device or resource busy
解决方案:
# 1. 找出关联容器
docker ps -q | xargs docker inspect --format '{{.State.Pid}} {{.Name}}' | grep $(fuser -vm /mnt/data)
# 2. 临时停用容器
docker stop container_name
# 3. 清理后重启
docker start container_name
IO 负载控制
大规模删除时用 ionice 降低优先级:
ionice -c 3 ./cleaner.py # 设置为空闲级别
延伸思考
长期解决方案可以结合对象存储:
- 将训练数据预先存放在 OSS/S3
- 用
rclone挂载到实例 - 设置生命周期策略自动清理旧数据
下次可以聊聊怎么用 rclone mount 实现这个方案~
正文完
