企业级存储优化实战指南
📖 目录导读
为什么需要大文件自动清理?
Q:手动清理和脚本清理有什么区别?
A:大型服务器或NAS存储中,日志、临时文件、压缩包等大文件会迅速消耗磁盘空间,手动查找不仅效率极低,且容易误删重要数据,定时脚本能实现:

- 按阈值(如>100MB)自动扫描
- 按最后修改时间(如30天未访问)过滤
- 自动执行删除/归档/压缩动作
- 生成清理报告邮件通知
Q:哪些场景最需要此脚本?
- 日志服务器(每天产生GB级日志)
- 媒体编辑工作站(渲染缓存堆积)
- 企业备份NAS(旧备份未自动轮替)
- 开发测试环境(依赖包和构建产物)
核心脚本设计原理
1 数据流架构
[磁盘扫描] → [过滤规则引擎] → [操作决策] → [执行清理] → [日志记录]
2 关键参数设计
| 参数 | 示例值 | 说明 |
|---|---|---|
| 扫描路径 | /data/logs/ | 建议细化到目录,避免扫描系统分区 |
| 文件大小阈值 | 500MB | 超过该值才进入候选列表 |
| 时间阈值 | 90天 | 仅处理指定时间内未修改的文件 |
| 排除模式 | .lock,.pid | 保护锁文件和进程文件 |
| 操作类型 | delete/archive | 删除或压缩后移动到归档目录 |
3 性能优化要点
- 使用
find命令的-size参数替代逐文件stat调用 - 对大目录启用
-maxdepth限制递归深度 - 采用
xargs -P实现并行处理(适合SSD场景)
手把手编写扫描清理脚本
1 基础版:单目录清理脚本
#!/bin/bash
# clean_large_files.sh
TARGET_DIR="/var/log/app"
THRESHOLD="+500M"
AGE="+30"
EXCLUDE_PATTERN="*.gz"
echo "[$(date)] 开始扫描 $TARGET_DIR 中超过 ${THRESHOLD} 且 ${AGE} 天未修改的文件"
find "$TARGET_DIR" -type f -size $THRESHOLD -mtime $AGE ! -name "$EXCLUDE_PATTERN" -print0 | \
while IFS= read -r -d '' file; do
filesize=$(du -h "$file" | cut -f1)
echo " [清理] $file (大小: $filesize)"
# 安全模式:先移动到回收站
mv "$file" "/tmp/recycle_bin/$(basename $file).$(date +%Y%m%d%H%M%S)"
done
# 压缩回收站(可选)
tar -czf "/backup/archive_$(date +%Y%m%d).tar.gz" -C /tmp/recycle_bin .
rm -rf /tmp/recycle_bin/*
echo "[$(date)] 清理完成,备份已存放至 /backup"
2 增强版:多规则配置文件
#!/bin/bash
# config_cleaner.sh
CONFIG_FILE="/etc/cleanup/clean_rules.conf"
# 配置文件格式示例:
# /data/logs 100M 90 delete *.zip
# /tmp/cache 500M 7 archive *.tmp
while IFS=' ' read -r dir size age action exclude; do
[[ "$dir" == "#"* ]] && continue # 跳过注释
echo "处理目录: $dir (标准: >$size, 修改>$age天, 排除:$exclude)"
find "$dir" -type f -size "+$size" -mtime "+$age" ! -name "$exclude" | \
while read file; do
case "$action" in
delete)
rm -f "$file"
logger "已删除过期大文件: $file"
;;
archive)
gzip "$file" && mv "$file.gz" "/archive/$(basename $file).gz"
;;
esac
done
done < "$CONFIG_FILE"
3 跨平台:Python版(支持Windows/Linux)
#!/usr/bin/env python3
# cross_platform_cleaner.py
import os, time, logging
from pathlib import Path
def clean_large_files(root_dir, max_size_mb=500, max_age_days=90, exclude_exts=[], action='delete'):
logging.basicConfig(filename='cleaner.log', level=logging.INFO)
now = time.time()
max_age_seconds = max_age_days * 86400
for file_path in Path(root_dir).rglob('*'):
if file_path.is_file():
ext = file_path.suffix.lower()
if ext in ['.'+e for e in exclude_exts]:
continue
size_mb = file_path.stat().st_size / (1024*1024)
age_seconds = now - file_path.stat().st_mtime
if size_mb >= max_size_mb and age_seconds >= max_age_seconds:
if action == 'delete':
file_path.unlink()
logging.info(f"已删除: {file_path} ({size_mb:.2f}MB)")
elif action == 'archive':
file_path.rename(file_path.with_suffix(file_path.suffix+'.old'))
if __name__ == '__main__':
clean_large_files('/var/log', max_size_mb=200, exclude_exts=['gz','zip'])
定时任务配置方法
1 Linux crontab 配置
# 每天凌晨2点执行清理 0 2 * * * /usr/local/bin/clean_large_files.sh >> /var/log/cleanup.log 2>&1 # 每周日凌晨3点执行深度清理 0 3 * * 0 /usr/local/bin/config_cleaner.sh
2 Windows 任务计划程序
触发器:每天 01:00
操作:启动程序 "python.exe"
参数:"D:\scripts\cross_platform_cleaner.py"
起始于:D:\scripts
3 容器化方案(Docker)
services:
cleaner:
image: alpine:latest
volumes:
- /data:/target
- ./scripts:/scripts
command: >
sh -c "apk add --no-cache bash &&
crond -f -l 2 &&
/scripts/clean_large_files.sh"
environment:
- CHECK_INTERVAL=3600
安全风险与避坑指南
1 必须规避的三大错误
-
误删系统文件
- 永远不要对 ,
/etc,/usr等系统目录执行递归扫描 - 设置白名单模式:
find使用-path排除系统路径
- 永远不要对 ,
-
删除正在写入的文件
# 错误做法:直接删除当前进程的文件会导致进程崩溃 rm /proc/1234/fd/3 # 危险! # 正确做法:使用lsof检查文件占用 lsof /data/logs/access.log | grep -q "mysqld" || rm /data/logs/access.log
-
权限不足导致任务失败
- 使用
sudo运行脚本时注意环境变量继承 - 日志目录权限:
chmod 640 /var/log/cleanup.log
- 使用
2 数据恢复保障方案
# 删除前创建软链接备份
BACKUP_DIR="/backup/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
while read file; do
ln -s "$file" "$BACKUP_DIR/$(basename $file | md5sum | cut -d' ' -f1)"
done < <(find /target -size +500M)
# 恢复时只需读取软链接的原始路径
常见问题FAQ
Q1:脚本扫描导致CPU和磁盘IO飙升怎么办?
→ 添加nice命令降低优先级:
nice -n 19 find /data -size +500M | xargs -P 1 rm
→ 在find中使用-maxdepth减少扫描范围
→ 对日志类文件可使用inotify实时监控替代全量扫描
Q2:如何只清理日志目录但保留最近7天的日志?
# 利用mtime参数 find /var/log -name "*.log" -mtime +7 -size +10M -delete # 更精确:保留最新版本 ls -1t /var/log/*.log | tail -n +30 | xargs rm
Q3:清理后如何发送报告?
# 使用mailx发送HTML报告
{
echo "Subject: Disk Cleanup Report $(date)"
echo "Content-Type: text/html"
echo ""
echo "<h3>清理摘要</h3>"
echo "<table border=1><tr><th>文件</th><th>大小</th><th>操作</th></tr>"
while read file; do
echo "<tr><td>$file</td><td>$(du -h "$file" | cut -f1)</td><td>已删除</td></tr>"
done < /tmp/deleted_files.txt
echo "</table>"
} | /usr/sbin/sendmail -t "admin@example.com"
Q4:遇到只读文件系统如何处理?
→ 在脚本中加入重试逻辑:
for i in range(3):
try:
os.unlink(file_path)
break
except PermissionError:
subprocess.run(['chattr', '-i', file_path])
time.sleep(5)
Q5:如何对特定用户(如mysql)的文件设置保留策略?
# 使用find的-user参数
find /home -user mysql -size +1G -mtime +90 -exec rm {} \;
# 或使用acl权限控制
setfacl -m u:mysql:--- /data/expired_dir
专业建议:在生产环境部署前,务必在测试环境运行脚本的
--dry-run模式,并开启脚本的日志功能,建议每周检查cleanup.log文件,结合磁盘使用率趋势图动态调整清理策略,对于关键业务数据,始终优先使用archive动作而非delete。