服务器磁盘空间不足怎么清理?磁盘爆满排查与清理完整指南

服务器磁盘空间不足是运维工作中最常见、也最容易引发严重故障的问题之一。磁盘一旦爆满,轻则日志无法写入、文件上传失败,重则数据库崩溃、服务彻底宕机。很多团队在业务上线初期对磁盘容量预估不足,随着日志堆积、数据增长,最终在某个时间点突然爆发。本文将从磁盘满的危害讲起,系统性地介绍排查方法、Linux和Windows两大平台的磁盘清理操作、自动化监控告警方案以及长效预防措施,帮助你建立一套完整的磁盘管理体系。
一、服务器磁盘空间不足的严重危害
很多人对磁盘满的危害认识不足,以为只是"存不下新文件"这么简单。实际上,磁盘空间不足的连锁反应远比想象中严重,以下是几种典型的危害场景:
1. 数据库写入失败甚至数据损坏。无论是MySQL、PostgreSQL还是MongoDB,数据库在执行写操作时都需要磁盘空间来存储数据文件、事务日志和临时表。当磁盘空间不足时,数据库会拒绝写入并抛出错误,如果此时正在执行事务,可能导致事务回滚失败,进而造成数据不一致甚至数据文件损坏。对于生产环境的数据库来说,这种故障往往需要花费大量时间修复,严重的甚至无法恢复。
2. Web服务异常与网站无法访问。Nginx、Apache等Web服务器需要写入访问日志和错误日志,当磁盘满后日志写入失败,部分服务器会因此停止响应请求。更严重的是,如果网站有文件上传功能(如用户头像、附件上传),上传操作会因为无法写入磁盘而失败,用户会看到500错误。对于电商、SaaS等线上业务,这种故障直接影响营收。
3. 日志丢失影响故障排查。当磁盘接近满时,系统可能自动截断或覆盖旧日志,导致关键时刻的日志丢失。等到你事后排查问题时,发现相关日志已经不存在了,大大增加了故障定位的难度。
4. 系统服务异常退出。Linux系统的很多守护进程依赖临时文件和PID文件正常运行,磁盘满后这些文件无法创建,服务会异常退出。SSH服务也可能受到影响,导致你无法远程登录服务器进行修复,只能通过控制台或重启服务器来处理。
二、排查磁盘占用:先看整体再看明细
服务器磁盘空间不足时,第一步不是盲目删除文件,而是要先搞清楚空间到底被什么占用了。排查的基本思路是:先看整体分区使用情况,再逐层深入定位到具体的大文件和大目录。
2.1 用 df 查看分区整体使用情况
df命令用于显示文件系统的磁盘空间使用情况,是排查的第一步。重点关注Use%(使用率)和Avail(可用空间)两列。
# 以人类可读格式查看磁盘使用情况(KB/MB/GB自动转换)
df -h
# 输出示例:
# Filesystem Size Used Avail Use% Mounted on
# /dev/vda1 40G 38G 1.2G 97% /
# /dev/vdb1 100G 45G 55G 45% /data
当使用率超过85%就应该开始关注,超过90%需要尽快处理,超过95%属于紧急情况。需要特别注意一个细节:ext4等文件系统默认会为root用户保留5%的空间(通过tune2fs可以调整),这意味着普通用户在磁盘使用率达到95%之前就会遇到"空间不足"的错误。
2.2 用 du 定位大目录和大文件
df只能看到分区整体情况,要知道具体是哪个目录占用了空间,需要用du命令逐层排查。
# 查看根目录下各一级目录的占用大小,按从大到小排序
du -sh /* 2>/dev/null | sort -rh | head -20
# 深入查看占用最大的目录,例如 /var
du -sh /var/* 2>/dev/null | sort -rh | head -20
# 继续深入到下一层
du -sh /var/log/* 2>/dev/null | sort -rh | head -20
这种逐层深入的方法非常实用:先找到根目录下最大的目录,然后进入该目录继续排查,通常两三层就能定位到占用空间最大的具体文件。参数-s表示只显示汇总大小,-h表示人类可读格式,2>/dev/null用于屏蔽权限不足的报错信息。
2.3 用 find 查找大文件
除了按目录排查,也可以直接用find命令查找超过指定大小的文件。
# 查找整个系统中大于100MB的文件
find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null
# 查找最近7天内修改过的大文件(可能是异常增长的数据)
find / -type f -size +50M -mtime -7 -exec ls -lh {} \; 2>/dev/null
这种方法适合快速找出异常的大文件,比如某个应用突然生成了几个GB的日志文件,用find能很快发现。
2.4 排查 inode 耗尽问题
有一种特殊情况需要注意:磁盘空间还有剩余,但系统却报"no space left on device"。这通常不是空间不足,而是inode耗尽。每个文件(无论大小)都会占用一个inode,当文件数量过多时inode就会耗尽,即使磁盘空间还有剩余也无法创建新文件。
# 查看inode使用情况
df -i
# 统计各目录下的文件数量,找出小文件最多的目录
for d in /*; do echo "$(find $d 2>/dev/null | wc -l) $d"; done | sort -rn | head -10
inode耗尽常见于以下场景:邮件队列堆积大量小邮件、PHP session文件未清理、缓存系统(如Redis持久化文件碎片)、日志切割配置不当产生大量小日志文件。解决方法是清理多余的小文件,或者将数据迁移到inode更充足的分区。
三、Linux系统磁盘清理方法详解
定位到占用空间的文件后,就可以开始针对性的磁盘清理了。Linux系统下主要有以下几个清理方向:日志文件、软件包缓存、临时文件、Docker镜像和旧内核。
3.1 清理日志文件
日志是磁盘空间的头号消耗者。系统日志通常在/var/log目录,应用日志则分布在各自的安装目录下。长时间运行的服务器如果不做日志管理,日志文件会持续增长。
# 查看各日志文件大小
du -sh /var/log/* | sort -rh | head -10
# 清空日志文件内容(不删除文件本身,服务仍可正常写入)
> /var/log/messages
> /var/log/syslog
# 删除超过7天的旧日志文件
find /var/log -name "*.log" -mtime +7 -exec rm -f {} \;
# 压缩归档历史日志(保留内容但节省空间)
find /var/log -name "*.log" -mtime +3 -exec gzip {} \;
这里有一个重要细节:不要直接用rm删除正在被写入的日志文件。在Linux中,如果一个进程正在打开某个文件,即使你删除了文件,磁盘空间也不会立即释放——因为文件描述符还在,进程仍然持有该文件的引用。正确的做法是先清空文件内容(用>重定向),或者重启对应的服务。这也是为什么>清空方式比rm删除更安全的原因。
更推荐的做法是配置logrotate日志轮转,让系统自动管理日志的切割、压缩和清理:
# 查看logrotate主配置
cat /etc/logrotate.conf
# 查看各服务的轮转配置
ls /etc/logrotate.d/
# 示例:为应用配置日志轮转
# /opt/myapp/logs/*.log {
# daily # 每天轮转一次
# rotate 30 # 保留30天的日志
# compress # 压缩旧日志
# missingok # 日志不存在时不报错
# notifempty # 空文件不轮转
# copytruncate # 清空当前日志而不是新建文件(不影响正在写入的进程)
# }
3.2 清理软件包缓存
使用yum或apt包管理器安装软件时,下载的安装包会缓存在本地,日积月累也会占用不少空间。
# CentOS/RHEL 系统清理yum缓存
yum clean all
# 查看缓存占用
du -sh /var/cache/yum/
# Ubuntu/Debian 系统清理apt缓存
apt clean
# 清理已下载的deb包和过期的包索引
du -sh /var/cache/apt/archives/
对于CentOS系统,还可以清理旧版本的软件包。yum在更新软件时会保留旧版本以便回滚,这些旧版本会占用额外空间:
# 查看已安装的旧版本软件包
package-cleanup --oldkernels --count=2
# 清理无用的依赖包
yum autoremove
3.3 清理临时文件
系统临时目录/tmp和/var/tmp用于存放程序运行时的临时文件。正常情况下系统会定期自动清理,但如果程序异常退出,临时文件可能残留。应用自身的临时目录(如Tomcat的work目录)也需要关注。
# 查看临时目录大小
du -sh /tmp /var/tmp
# 删除超过7天未修改的临时文件
find /tmp -type f -mtime +7 -exec rm -f {} \;
find /var/tmp -type f -mtime +7 -exec rm -f {} \;
注意清理/tmp时不要删除正在使用的文件,否则可能导致正在运行的程序出错。建议先通过lsof | grep /tmp查看哪些文件正在被使用。
3.4 清理Docker镜像与容器
如果服务器上运行了Docker,镜像是磁盘占用的重灾区。每次构建镜像都可能产生中间层,停止的容器和悬空镜像也会残留。
# 查看Docker磁盘占用
docker system df
# 清理所有未使用的镜像、容器、网络和构建缓存
docker system prune -a
# 只清理悬空镜像(没有标签的中间层镜像)
docker image prune
# 清理已停止的容器
docker container prune
docker system prune -a会删除所有未被容器使用的镜像,效果彻底但需要谨慎使用——确保你要用的镜像都有对应的运行中容器,否则会被一并清理。
3.5 清理旧内核
CentOS系统在执行yum update更新时,默认会保留多个旧版本内核。每个内核大约占用几十到上百MB空间。
# 查看当前使用的内核版本
uname -r
# 查看已安装的所有内核
rpm -qa | grep kernel
# 删除旧版本内核,仅保留当前使用的版本(CentOS 7+)
package-cleanup --oldkernels --count=1
四、Windows服务器磁盘清理方法
Windows服务器同样会遇到磁盘空间不足的问题,尤其是运行IIS、SQL Server的服务器。Windows的磁盘清理方式与Linux不同,以下是几种常用方法。
4.1 使用磁盘清理工具
Windows自带磁盘清理工具,可以清理临时文件、回收站、Windows更新缓存等。
# 打开磁盘清理工具(通过运行)
cleanmgr
# 命令行方式,自动清理C盘
cleanmgr /d C: /sageset:1
在磁盘清理工具的界面中,可以勾选要清理的项目,包括:Windows更新清理(通常能释放几个GB)、临时文件、回收站、传递优化文件、缩略图缓存等。其中Windows更新清理往往是释放空间最多的一项。
4.2 清理IIS日志文件
IIS的日志文件默认存放在C:\inetpub\logs\LogFiles目录下,随着访问量增加会持续增长,是Windows服务器磁盘空间的常见消耗者。
# 查看IIS日志目录大小(在PowerShell中执行)
Get-ChildItem "C:\inetpub\logs\LogFiles" -Recurse | Measure-Object -Property Length -Sum
# 删除超过30天的IIS日志
Get-ChildItem "C:\inetpub\logs\LogFiles" -Recurse -Filter "*.log" | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } | Remove-Item
建议同时修改IIS日志配置,限制单个日志文件大小或定期滚动,从根源上控制日志增长。
4.3 清理Windows更新缓存
Windows更新下载的安装文件缓存在C:\Windows\SoftwareDistribution\Download目录,更新完成后这些文件不再需要但不会被自动删除。
# 停止Windows更新服务
net stop wuauserv
net stop bits
# 删除更新缓存文件
Remove-Item -Path "C:\Windows\SoftwareDistribution\Download\*" -Recurse -Force
# 重新启动服务
net start wuauserv
net start bits
4.4 清理临时文件和回收站
# 清理用户临时文件
Remove-Item -Path "$env:TEMP\*" -Recurse -Force -ErrorAction SilentlyContinue
# 清理系统临时文件
Remove-Item -Path "C:\Windows\Temp\*" -Recurse -Force -ErrorAction SilentlyContinue
# 清空回收站
Clear-RecycleBin -Force
五、磁盘扩容方案
当磁盘清理后空间仍然紧张,就需要考虑扩容。扩容方式取决于服务器的部署形态,以下是常见方案的对比:
| 服务器类型 | 扩容方式 | 是否需要停机 | 操作难度 | 说明 |
|---|---|---|---|---|
| 云服务器(阿里云/腾讯云/AWS) | 控制台在线扩容云盘 | 无需停机 | 低 | 扩容后需在系统内扩展分区和文件系统 |
| 物理服务器 | 加装新硬盘并挂载 | 可能需要短暂停机 | 中 | 需要物理安装硬盘,在系统中分区格式化并挂载 |
| 虚拟机(VMware等) | 扩展虚拟磁盘容量 | 建议关机操作 | 中 | 先在虚拟化平台扩容,再在系统内扩展分区 |
| NAS/共享存储 | 扩展存储池或卷 | 无需停机 | 低 | 按需增加容量,适合数据持续增长的场景 |
云服务器扩容系统盘后,新增的空间不会自动使用,需要手动扩展分区和文件系统:
# 查看当前分区情况
lsblk
# 扩展分区(以 /dev/vda 的第1分区为例)
growpart /dev/vda 1
# 扩展ext4文件系统
resize2fs /dev/vda1
# 如果是xfs文件系统,则使用:
xfs_growfs /
# 确认扩容结果
df -h
六、自动化监控与告警
磁盘清理是治标,建立自动化监控告警才是治本之道。通过监控,你可以在磁盘使用率达到80%时就收到告警,提前处理,避免等到爆满才手忙脚乱。
6.1 编写磁盘监控告警脚本
以下是一个实用的磁盘监控脚本,当使用率超过阈值时发送告警邮件,并记录到日志:
#!/bin/bash
# 磁盘空间监控告警脚本
# 配置告警阈值(百分比)
THRESHOLD=85
# 收件人邮箱
ALERT_EMAIL="admin@example.com"
# 获取本机IP
HOSTNAME=$(hostname)
# 遍历各分区,检查使用率
df -H | awk '{print $5 " " $6}' | grep -vE '^Use|^Filesystem' | while read line; do
USAGE=$(echo $line | awk '{print $1}' | sed 's/%//g')
PARTITION=$(echo $line | awk '{print $2}')
if [ "$USAGE" -ge "$THRESHOLD" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') 警告:分区 $PARTITION 使用率 ${USAGE}%,超过阈值 ${THRESHOLD}%" >> /var/log/disk-monitor.log
# 发送告警邮件(需要配置邮件服务)
echo "服务器 ${HOSTNAME} 磁盘告警:分区 ${PARTITION} 使用率已达到 ${USAGE}%,请及时处理。" | mail -s "磁盘空间告警-${HOSTNAME}" $ALERT_EMAIL
fi
done
# 将监控脚本加入crontab,每小时执行一次
crontab -e
# 添加以下内容:
# 0 * * * * /root/scripts/disk-monitor.sh
6.2 配置自动化磁盘清理
除了监控告警,还可以配置定时自动清理脚本,定期清理旧日志和临时文件,防患于未然:
#!/bin/bash
# 自动化磁盘清理脚本
# 日志目录
LOG_DIR="/var/log"
APP_LOG_DIR="/opt/myapp/logs"
TMP_DIR="/tmp"
# 1. 删除超过30天的旧日志
find $LOG_DIR -name "*.log" -mtime +30 -exec rm -f {} \;
find $APP_LOG_DIR -name "*.log" -mtime +30 -exec rm -f {} \; 2>/dev/null
# 2. 清理临时目录中超过7天的文件
find $TMP_DIR -type f -mtime +7 -exec rm -f {} \;
# 3. 清理软件包缓存(自动判断包管理器)
if command -v yum &> /dev/null; then
yum clean all
elif command -v apt &> /dev/null; then
apt clean
fi
# 4. 清理Docker无用资源(如果安装了Docker)
if command -v docker &> /dev/null; then
docker system prune -f --filter "until=168h"
fi
# 5. 清理后记录磁盘状态
echo "========== $(date '+%Y-%m-%d %H:%M:%S') ==========" >> /var/log/disk-clean.log
df -h >> /var/log/disk-clean.log
# 每周日凌晨3点自动执行清理
crontab -e
# 0 3 * * 0 /root/scripts/auto-cleanup.sh
6.3 使用专业监控工具
对于有多台服务器的运维场景,建议使用专业监控工具来实现更完善的磁盘监控:
Zabbix:开源监控系统,自带磁盘空间监控模板,支持自定义告警阈值和多种告警渠道(邮件、短信、钉钉、企业微信)。Prometheus + Grafana:云原生监控方案,通过node_exporter采集磁盘指标,Grafana可视化展示,配合Alertmanager实现告警。云平台自带监控:阿里云、腾讯云等云厂商都提供云监控服务,可以设置磁盘使用率告警规则,无需额外安装软件。
七、预防磁盘空间不足的最佳实践
与其等问题出现再处理,不如从架构和运维流程上做好预防。以下是几条经过实践验证的有效措施:
1. 合理规划磁盘分区。不要把所有数据都放在根分区下。建议将日志、数据库数据、应用数据分别挂载到独立的分区或磁盘上。这样即使某个分区满了,也不会影响系统核心功能。例如:/var/log单独分区、数据库数据目录单独挂载数据盘。
2. 配置日志轮转策略。所有产生日志的服务都应该配置logrotate,设置合理的保留天数和压缩策略。一般建议:业务日志保留30天,系统日志保留14天,访问日志保留7天,超过期限自动压缩归档或删除。
3. 定期执行磁盘清理。将自动清理脚本加入crontab定期执行,不要等到磁盘满了才手动清理。建议每周执行一次常规清理,每月做一次深度清理。
4. 设置磁盘监控告警。监控阈值建议设置为:80%预警、90%警告、95%紧急。确保在磁盘满之前就能收到告警并处理。同时要定期检查告警是否正常工作,避免告警失效却浑然不知。
5. 关注数据增长趋势。不要只看当前使用率,还要关注增长趋势。如果磁盘使用率每月增长10%,即使现在只有50%,三个月后也会达到80%。根据增长趋势提前规划扩容。
6. 规范日志和临时文件管理。应用开发时就应考虑日志和临时文件的管理:日志要有级别控制和大小限制,临时文件用完即删,避免程序异常退出后残留临时文件。
7. 容器环境特殊注意。Docker环境下要特别注意镜像和容器卷的清理。建议为容器配置日志驱动(如json-file配置max-size和max-file参数),避免单个容器日志无限增长。定期执行docker system prune清理无用资源。
服务器磁盘空间不足看似是小问题,但引发的影响往往是连锁性的、灾难性的。建立"监控预警—定期清理—合理扩容"的三层防护体系,才能从根本上避免磁盘爆满带来的运维事故。希望本文的排查方法和清理方案能帮助你有效解决磁盘空间问题。
相关阅读:
