网站突然打不开,数据库连接失败,后台登录不进去,重启服务器也没用。
这种时候先别慌着查代码,跑一条命令:
df -h
如果某个分区 Use% 显示 100%,原因就找到了。而且我可以先告诉你最可能的元凶:MySQL 的 binlog 日志。
一、为什么磁盘满了网站会完全挂掉
MySQL 写不进数据就会拒绝连接,WordPress 拿不到数据直接报错;PHP 写不了 session 文件,用户全部登录失败;nginx 写不了访问日志,请求直接 500。
所以磁盘满不是”慢一点”,是整站瘫痪。而且很多人遇到这种情况第一反应是重启——重启解决不了磁盘满,白白浪费时间。
二、3 分钟定位到底是谁占满了
第一步:确认哪个分区满了
df -h
一般是 / 根分区。
第二步:找出占空间的大目录
du -sh /* 2>/dev/null | sort -rh | head -15
然后一层层往下钻,比如发现 /www 最大,就:
du -sh /www/* 2>/dev/null | sort -rh | head -15
第三步:几种常见”大户”
| 占用来源 | 典型路径 | 能不能删 |
|---|---|---|
| MySQL binlog | /www/server/data/ 或 /var/lib/mysql/ 下的 mysql-bin.0000xx |
能,但要按规矩清 |
| 网站访问日志 | /www/wwwlogs/ |
能删,但先保留最近的 |
| 数据库慢日志/错误日志 | /www/server/data/*.err |
能删 |
| 站点备份文件 | /www/backup/ |
看情况,异地备份过的可删 |
| 未清理的临时文件 | /tmp/ |
基本都能删 |
| 已删除但被进程占用的文件 | 无路径(句柄) | 重启对应进程才释放 |
一个容易踩的坑:文件删了但空间没释放
如果你用 rm 删了大文件,df -h 显示空间没变,是因为那个文件还被某个进程占着。查:
lsof | grep deleted
找到对应的进程(通常是 mysqld 或 nginx),重启它,空间才会真正释放。
三、binlog:撑爆磁盘的头号选手
binlog 是 MySQL 的二进制日志,记录所有数据变更。它的作用是数据恢复和主从同步。如果你没做主从复制,它对你唯一的价值就是”万一要恢复到某个时间点”。
问题是:它默认不会自动清理。一个日访问几千的站,binlog 能以每天几百 MB 的速度增长。我见过 40G 的硬盘被 binlog 吃到 39G。
看看你的 binlog 占了多大
du -sh /www/server/data/mysql-bin.* 2>/dev/null | tail -1 # 或进 MySQL 看 mysql -uroot -p -e "SHOW BINARY LOGS;"
安全清理(推荐做法)
登录 MySQL,按时间清理:
-- 清理 3 天前的所有 binlog PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY); -- 或清理到某个具体文件之前 PURGE BINARY LOGS TO 'mysql-bin.000123';
不要用 rm 直接删 binlog 文件,会导致 MySQL 索引错乱,下次启动可能起不来。
治本:设置自动过期
MySQL 5.7 / 8.0 在配置文件加:
[mysqld] expire_logs_days = 3 # 8.0 用 binlog_expire_logs_seconds max_binlog_size = 100M
MySQL 8.0 推荐:
binlog_expire_logs_seconds = 259200 # 3天
改完重启 MySQL 生效。
如果你根本用不到 binlog
单服务器、没有主从同步的独立站,其实可以直接关掉 binlog,省事又省空间。在 my.cnf 里注释掉 log-bin 那行,重启 MySQL。
代价是:就不能做”恢复到某一秒”的点对点恢复了。但如果你本来就是每天全量备份,这个代价可以接受——大不了丢一天数据,而实际上独立站丢一天数据的概率极低。
怎么选?
- 电商站有订单:保留 binlog,设 3 天过期
- 纯展示型企业站:直接关掉,靠每日全量备份
四、日志:另一个慢性杀手
网站访问日志看着不大,但高流量站一天几百 MB 很正常。而且宝塔默认不自动切割,一个 access.log 能长到十几 G。
开启日志切割
宝塔面板:站点设置 → 日志 → 开启”日志切割”,设置保留天数(建议 7-14 天)。
或者用系统自带的 logrotate,配置 /etc/logrotate.d/nginx:
/www/wwwlogs/*.log {
daily
rotate 14
compress
missingok
notifempty
create 0644 www www
postrotate
[ -f /www/server/nginx/logs/nginx.pid ] && kill -USR1 `cat /www/server/nginx/logs/nginx.pid`
endscript
}
处理已经被写爆的日志文件
注意:不要直接 rm access.log。nginx 还持有这个文件句柄,你删了它还会继续往那个已删除的文件写,空间不释放。
正确做法是清空:
> /www/wwwlogs/你的站点.log
这个命令把文件内容截断为 0,不影响 nginx 的句柄,空间立刻释放。
五、让它不再发生:三道防线
1. 磁盘告警
宝塔面板 → 设置 → 告警,开启磁盘告警,阈值设 80%。或者用免费的监控服务(UptimeRobot 的磁盘监控、Server酱推送)。
关键是要提前知道,而不是等网站挂了才发现。
2. 定期清理自动化
写个脚本放 cron,每周跑一次:
#!/bin/bash # 清理 7 天前的日志 find /www/wwwlogs -name "*.log-*" -mtime +7 -delete # 清理临时文件 find /tmp -type f -mtime +7 -delete # MySQL 清理 3 天前 binlog mysql -uroot -p密码 -e "PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY);"
3. 备份异地化
本地备份文件也是磁盘大户。备份一定要传到异地(对象存储、另一台机器、网盘),本机只保留最近 2-3 份。
这不只是省空间的问题——服务器整个挂掉的时候,本地备份跟着一起没。
最后
磁盘满这件事,处理本身不难,难的是它总是在你不注意的时候发生。
花 20 分钟把 binlog 过期、日志切割、磁盘告警三件事配好,能省掉未来某一天几个小时的救火。运维里绝大多数”事故”,都是本可以用十分钟配置避免的。