PHP项目如何排查服务器磁盘爆满?

wen PHP项目 55

PHP项目服务器磁盘爆满:系统级排查与根治方案(含实战问答)

📖 目录导读

  1. 问题现象与紧急止损
  2. 快速定位异常大文件(含Linux命令实战)
  3. PHP项目特有“磁盘黑洞”诱因
  4. 日志、SESSION、缓存三大元凶深挖
  5. 脏数据与幽灵进程清理
  6. 监控预警与自动化脚本
  7. 常见问答(Q&A)
  8. 从被动排查到主动防御

问题现象与紧急止损

典型场景:PHP项目(如Laravel、ThinkPHP)运行数月后,服务器突然报警“磁盘空间使用率99%”,导致数据库写入失败、用户上传图片报错甚至网站白屏。

PHP项目如何排查服务器磁盘爆满?

第一步:紧急止血

df -h   # 查看各分区使用率
du -sh /var/log   # 快速检查日志分区是否爆满

若主分区(通常为或/var)使用率接近100%,立即执行:

  • 清空临时目录:rm -rf /tmp/* (注意:部分PHP进程会写入/tmp
  • 暂停非核心服务:如systemctl stop php-fpm,防止进程继续写盘。

注意:切勿在生产高峰期直接重启服务器,需先定位具体文件后再清理。


快速定位异常大文件(核心命令)

使用finddu组合拳定位“磁盘杀手”:

1 查找超过1GB的文件

find / -type f -size +1G -exec ls -lh {} \; | sort -k5 -hr | head -20

2 分析PHP项目目录结构

du -sh /www/wwwroot/*/runtime   # 检查框架运行时目录(如ThinkPHP的runtime)
du -sh /www/logs/               # 检查应用日志目录

3 隐藏的“磁盘黑洞”:inode耗尽

即使df -h显示剩余空间,也可能出现“No space left”报错,原因可能是inode耗尽:

df -i   # 查看inode使用率
find / -xdev -printf '%h\n' | sort | uniq -c | sort -rn | head -10

常见诱因:大量会话文件(SESSION)、缓存碎片、上传目录中成千上万的缩略图。


PHP项目特有“磁盘黑洞”诱因

PHP项目比其他语言(如Java)更易产生磁盘问题,根本原因在于:

  • SESSION文件未自动清理:默认PHP会话存储在/tmp/sess_*/var/lib/php/sessions,若gc_maxlifetime设置过长,文件会堆积。
  • 日志轮转失效:Laravel日志(storage/logs/laravel.log)重写写入模式,长期不轮转。
  • 缓存文件膨胀:Redis/Memcached的磁盘溢出缓存(如swap)、文件缓存(如cache/*)。

实战案例:某电商平台PHP项目每周产生2GB日志文件,排查后发现:

# 检查Laravel日志大小
ls -lh storage/logs/laravel-*.log | awk '{print $5, $9}'

日志文件laravel-2024-12-01.log达到1.8GB。


日志、SESSION、缓存三大元凶深挖

1 日志清理与轮转策略

# 对超30天的日志进行压缩归档
find /www/logs -name "*.log" -mtime +30 -exec gzip {} \;
# 配置logrotate(关键)
cat > /etc/logrotate.d/php-app << EOF
/www/logs/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
    postrotate
        /bin/kill -USR1 $(cat /var/run/php-fpm.pid 2>/dev/null)
    endscript
}
EOF

2 SESSION文件批量清理

# 查看当前会话文件数
ls /tmp/sess_* | wc -l
# 手动清理超过1天未修改的SESSION
find /tmp -name "sess_*" -atime +1 -delete
# PHP.ini关键参数优化
session.gc_maxlifetime = 1440   # 调整为24分钟
session.gc_probability = 1
session.gc_divisor = 100

3 缓存与临时文件清理

对于使用file缓存的应用(如ThinkPHP的temp目录):

find /www/wwwroot/app/runtime -type d -name "Cache" -exec rm -rf {} \;
rm -rf /tmp/php*   # 清理php临时上传文件残留

脏数据与幽灵进程清理

1 被删除但仍被进程占用的文件

某些进程可能打开了一个大文件后又删除了,但文件描述符未释放,导致磁盘空间虚假占用:

lsof | grep '(deleted)' | sort -k7 -rn | head -10
# 找到对应PID后重启进程
kill -HUP <PID>

2 数据库Binlog与慢查询日志

MySQL日志也是常见磁盘杀手:

-- 查看binlog占用
SHOW BINARY LOGS;
-- 清理过期binlog
PURGE BINARY LOGS BEFORE '2024-12-01 00:00:00';

同时检查/var/lib/mysql/下的ibdata1是否异常增长(通常是未启用独立表空间)。


监控预警与自动化脚本

1 磁盘告警脚本(Shell)

#!/bin/bash
THRESHOLD=80
CURRENT=$(df -h / | awk 'NR==2 {print $5}' | cut -d'%' -f1)
if [ $CURRENT -gt $THRESHOLD ]; then
    du -sh /www/logs /tmp /var/log | mail -s "Disk Warning" admin@yourdomain.com
fi

2 PHP项目专属监控点

  • 挂载监控:检查/tmp/var/lib/php/sessions是否独立分区(避免主分区爆满)
  • 文件数监控find /www -type f | wc -l 超过50万触发告警
  • 日志增长速率watch -n 60 'du -sh /var/log/php-fpm'

常见问答(Q&A)

问1:为什么df -h显示剩余20%,但写入文件仍报错?
答:大概率是inode耗尽,执行df -i检查,常见于上传目录(public/uploads)有数十万个小文件(如用户头像缩略图)。

问2:清理日志后,PHP-FPM进程没有释放空间怎么办?
答:使用lsof | grep '(deleted)'找到被删除但仍被占用的文件(如/var/log/php-fpm/error.log被重命名但未重启进程),需重启对应的PHP-FPM进程。

问3:Laravel项目storage/logs下的laravel-2025-01-01.log为什么无法删除?
答:可能原因:

  1. 文件权限问题(chmod 644chown www:www
  2. 该文件正被tail -flog viewer程序打开
  3. 启用了SELinux(检查ls -Z,使用restorecon -R解决)

问4:如何让PHP会话文件自动定期清理?
答:配置php.inisession.gc_divisor=100session.gc_probability=1,配合systemctl restart php-fpm生效,也可使用crontab定时清理:

0 */6 * * * find /tmp -name "sess_*" -mmin +30 -delete

问5:用户上传文件直接导致磁盘满,如何预防?
答:建议:

  1. 对上传文件大小做上限(upload_max_filesizepost_max_size
  2. 使用分布式文件系统(如OSS、S3)或单独挂载容量大的磁盘分区
  3. 设置上传目录定期清理脚本(如mtime +7删除临时文件)

从被动排查到主动防御

磁盘爆满的根源往往不是空间不足,而是管理缺失,本文建议三步走:

  1. 应急定位df -hfind大文件 → lsof删除文件
  2. 根源修复:配置日志轮转、会话清理、inode监控
  3. 长期防御:部署磁盘告警脚本+定期巡检PHP项目特有的日志、SESSION、缓存目录

推荐为PHP项目单独挂载/var/log/tmp分区,限制/tmp最大为5GB,避免应用日志反噬系统盘。

抱歉,评论功能暂时关闭!