必须监控 storage/app 磁盘使用率并触发邮件告警,当 ≥85% 时立即通知;同时自动清理 public 磁盘下 30 天未访问的图片文件,避免磁盘耗尽导致上传失败、队列卡死或 500 错误。

当 Laravel 应用中上传文件激增、用户头像批量导入或日志归档任务持续运行时,storage/app 目录可能在数小时内填满磁盘,导致上传失败、队列卡死甚至整个应用 500 错误。必须在磁盘使用率突破临界点前触发告警并记录空间趋势,而非等运维手动 df -h 发现问题。
监控 storage/app 磁盘使用率并触发邮件告警
这一步直接读取操作系统级磁盘信息,不依赖 PHP 文件遍历,响应快且结果真实。
创建 Artisan 命令:php artisan make:command CheckStorageUsage
在 app/Console/Commands/CheckStorageUsage.php 的 handle() 方法中,执行 shell_exec('df -P /var/www/project/storage/app | tail -1') 获取挂载点行;用 preg_match 提取第五列(已用百分比数字),去掉 % 符号后转为整型。
若数值 ≥ 85,则调用 Notification::route('mail', config('admin.disk_alert_email'))->notify(new StorageFullAlert($usage)); 发送含当前使用率与服务器主机名的邮件。注意:该阈值不可设为 90%,【Linux ext4 文件系统在使用率超 85% 后会显著降低写入性能,且部分临时文件操作可能因预留空间不足而失败】。
将命令加入 crontab 每 5 分钟执行一次:*/5 * * * * cd /var/www/project && php artisan storage:check >> /dev/null 2>&1
自动清理过期上传文件并记录清理日志
仅监控不清理等于放任风险累积。本方法针对 public 磁盘下超过 30 天未访问的图片文件做安全清理,避免误删正在使用的资源。
方法一:基于文件最后访问时间(atime)清理
在 storage/app/public/uploads 目录下,执行 find . -type f -name "*.jpg" -atime +30 -delete 2>/dev/null
方法二:结合数据库标记清理(更精准)
先确保上传逻辑中已记录文件元数据到 uploads 表,含 path、created_at、last_accessed_at 字段;再执行 DB::table('uploads')->where('last_accessed_at', 'subDays(30))->chunk(100, function ($batch) { foreach ($batch as $item) { Storage::disk('public')->delete($item->path); } });
无论用哪种方法,清理后必须写入日志:Log::channel('daily')->info("Cleaned {$deletedCount} expired upload files from public disk");
配置多模态存储驱动并启用磁盘配额告警
Laravel 13 支持按 MIME 类型路由到不同磁盘,可对高风险类型(如 video/*)单独设置空间上限并告警。
第一步:在 config/filesystems.php 中定义 videos 磁盘,指定 root => storage_path('app/videos'),并添加 'quota_mb' => 2048 配置项
第二步:编写定时检查脚本,读取该目录总大小:$size = (int)shell_exec("du -sm " . storage_path('app/videos') . " 2>/dev/null | cut -f1");
第三步:若 $size > config('filesystems.disks.videos.quota_mb'),则触发钉钉机器人通知,消息体包含当前用量、配额上限及 top 5 最大文件路径(通过 du -sh storage/app/videos/* 2>/dev/null | sort -hr | head -5 获取)











