Linux服务器磁盘满了怎么清理?从定位到根治的完整流程(实例)
凌晨3点,告警:服务器磁盘使用率100%,服务挂了。
爬起来排查,记录一下处理过程,以后遇到类似问题能快速定位。这篇文章不仅还原了当时的每一步操作,还补充了大量背景知识、注意事项和长期治理方案,希望能帮你从“应急救火”走向“主动预防”。
一、快速定位占用大户
1.1 查看整体磁盘使用
df -h
输出:
Filesystem Size Used Avail Use% Mounted on /dev/vda1 100G 100G 0 100% /
确认是根目录(/)满了。
这里补充一下:df -h 中的 -h 表示人类可读格式(GB/MB),Use% 列显示使用百分比。如果根目录达到 95% 以上,系统就可能出现写日志失败、服务异常甚至进程崩溃。另外还有一个常用命令 df -i 查看 inode 使用率,后面会单独讲到。
1.2 找出占用大的目录
# 查看根目录下各目录大小 du -sh /* 2>/dev/null | sort -rh | head -20
输出:
50G /var 30G /home 10G /usr 5G /opt
/var 目录占了50G,继续往下查。
这里用 du -sh /* 统计根目录下每个一级目录的大小,-s 表示汇总,-h 人类可读。注意这个命令执行时间较长,如果服务器 I/O 压力大,建议用 du -h --max-depth=1 / 分层进行,避免一次扫太多。
1.3 逐层定位
du -sh /var/* | sort -rh | head -10
输出:
45G /var/log 3G /var/lib 1G /var/cache
是日志文件占满了。
继续深入 /var/log:
du -sh /var/log/* | sort -rh | head -10
输出:
40G /var/log/app 3G /var/log/nginx 1G /var/log/messages
找到了:/var/log/app 目录有40G。
这个目录下通常是业务应用的自定义日志,有的应用会按天或按大小滚动,但如果没有配置轮转策略,就会无限增长。
二、查看具体是哪些文件
ls -lhS /var/log/app/ | head -20
输出:
-rw-r--r-- 1 root root 20G Dec 5 03:00 app.log -rw-r--r-- 1 root root 10G Dec 4 00:00 app.log.1 -rw-r--r-- 1 root root 5G Dec 3 00:00 app.log.2
一个日志文件20G,明显是日志没有做切割和清理。
使用 ls -lhS 可以按文件大小降序排列,快速揪出“胖子文件”。如果文件数量极多(比如数万个小文件),ls 会卡顿,此时可以用 find /var/log/app -type f -size +100M -exec ls -lh {} \; 只筛选大于100M的文件。
三、紧急处理
3.1 清空当前日志文件
不要直接删除! 如果直接 rm -f,进程可能仍持有该文件的文件描述符(file descriptor),空间不会真正释放,直到进程重启或退出。这是一个非常经典的运维陷阱。
正确的做法是清空文件内容,而不是删除文件本身:
# 正确做法:清空文件但保留文件描述符 cat /dev/null > /var/log/app/app.log # 或者 truncate -s 0 /var/log/app/app.log
这里使用 > logfile 重定向清空,或者 echo "" > logfile,也可以 cat /dev/null > logfile。清空后,进程继续写入同一个文件,空间立即释放。
⚠️ 注意:如果应用采用追加写入且文件被清空,有些程序会继续从偏移量0开始写,不会报错;但少数应用会检测文件变化并自动重开,具体需观察应用行为。
3.2 删除历史日志
如果目录下还有大量压缩或归档的旧日志(如 *.log.gz、*.log.1 等),可以按时间或数量进行删除:
# 删除7天前的日志 find /var/log/app/ -name "*.log.*" -mtime +7 -delete
这里 -mtime +7 表示修改时间在7天之前的文件,-name "*.log.*" 匹配历史轮转文件。建议先 find ... -ls 预览再执行 -delete。
3.3 验证空间释放
df -h
如果空间还是没释放,可能是有进程还在占用已删除的文件(注意:这里“已删除”指的是你用 rm 删除了但进程未释放,而上面我们用的是清空,所以一般不会出现)。但若你之前误用了 rm,可以用以下方法查找:
# 查看被删除但仍被占用的文件 lsof | grep deleted
lsof | grep deleted 会列出所有被删除但仍被进程打开的文件,第二列是PID。找到进程重启即可释放空间。
补充:有些场景无法立刻重启(如生产核心服务),可以尝试
> /proc/PID/fd/文件描述符号来清空,但操作风险较高,建议在业务低峰期重启。
四、根治:配置日志切割
手动清理只是治标,必须配置自动切割和过期清理。
4.1 使用logrotate
logrotate 是 Linux 系统自带的日志轮转工具,通过配置文件定义切割周期、保留份数、压缩方式等。
# /etc/logrotate.d/app
/var/log/app/*.log {
daily # 每天切割
rotate 7 # 保留7份
compress # 压缩
delaycompress # 延迟压缩
missingok # 文件不存在不报错
notifempty # 空文件不切割
create 644 root root
postrotate
# 切割后通知进程重新打开文件
kill -USR1 $(cat /var/run/app.pid) 2>/dev/null || true
endscript
}
这个配置表示:
- daily:每天轮转一次(也可以换成 size 1G 按大小触发)
- rotate 7:保留最近7个归档文件
- compress:用 gzip 压缩归档文件
- delaycompress:延迟压缩,保留最新一个不压缩(方便查看)
- missingok:如果日志文件不存在不报错
- notifempty:空文件不轮转
- create 0640 root root:轮转后新建空文件,权限和属主保持不变(避免应用写入失败)
- postrotate 脚本:重启 rsyslog 或应用服务,确保应用重新打开新文件(部分应用支持信号重载,可以用 kill -HUP PID)
常见应用示例:
- Nginx:/var/log/nginx/*.log,postrotate 为nginx -s reopen
- Tomcat:可以配合 cronolog 或直接使用 logrotate 的 copytruncate 模式(无需重启)
- Docker 容器日志:推荐使用docker logs驱动配合max-size和max-file参数
4.2 测试配置
# 测试配置是否正确 logrotate -d /etc/logrotate.d/app # 强制执行一次 logrotate -f /etc/logrotate.d/app
-d 为调试模式(dry-run),不实际执行,可查看轮转计划。确认无误后,logrotate 由 crond 每日自动运行(通常在 /etc/cron.daily/logrotate)。
五、常见磁盘空间占用大户
除了日志文件,以下几类也经常导致磁盘爆满,需要逐一排查。
5.1 日志文件
- 系统日志(
/var/log/messages、/var/log/syslog) - 应用日志(业务日志、访问日志、错误日志)
- 数据库日志(MySQL binlog、slow log,PostgreSQL WAL)
- 容器日志(Docker/containerd 默认存储在
/var/lib/docker/containers,单个容器日志可能无限增长)
| 类型 | 典型路径 | 排查命令 | 处理建议 |
|---|---|---|---|
| 系统日志 | /var/log/* | du -sh /var/log | 配置 rsyslog 限流 + logrotate |
| Web访问日志 | /var/log/nginx/* | ls -lhS /var/log/nginx | 按天切割,保留30天 |
| 数据库binlog | /var/lib/mysql | show binary logs; | 设置 expire_logs_days |
| Docker日志 | /var/lib/docker/containers | docker system df | 配置 daemon.json 的 log-opts |
5.2 临时文件
/tmp目录(系统临时文件,有些程序不自动清理)/var/tmp(持久临时文件,重启不会清空)- 会话文件(如 PHP session 存储于
/var/lib/php/session) - 上传临时文件(如 Nginx 的 client_body_temp,大文件上传遗留)
清理策略:建议定期 find /tmp -type f -atime +7 -delete(注意不要删除正在使用的文件)。
5.3 包管理器缓存
- yum(CentOS/RHEL):
/var/cache/yum,可执行yum clean all释放 - apt(Debian/Ubuntu):
/var/cache/apt/archives,可执行apt-get clean或apt autoclean - dnf:类似 yum
这些缓存通常不会自动删除,长期累积可能达数GB。
5.4 已删除但未释放的文件
前文已述,使用 lsof +L1 可查看所有被删除但仍有打开句柄的文件,+L1 显示 link count 为0的文件。常见于:
- 应用持续写日志,你直接 rm 删除了日志文件
- 临时文件被进程打开后,你手动删除了目录项
- 大文件被进程 mmap 映射
处理方法:重启对应进程,或清空 /proc/PID/fd/* 中的对应描述符(谨慎)。
六、实用排查命令大全
找大文件
# 找大于1G的文件
find / -type f -size +1G 2>/dev/null
# 找大于100M的文件并排序
find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null | sort -k5 -rh | head -20
这条命令会查找根目录下所有大于100M的文件,并按大小排序显示前10个。
进阶:如果文件数量极大,可以用
find / -xdev -size +100M -printf "%s %p\n" | sort -nr | head,避免ls排序开销。
查看inode使用
有时候磁盘空间还有剩余(比如 df -h 显示只用了 60%),但无法创建新文件,报错“No space left on device”。这时要检查 inode:
df -i
IUse% 列达到 100% 表示 inode 耗尽。inode 是文件系统中存储文件元数据的索引节点,每个文件(包括目录)至少占用一个 inode。
inode满了一般是小文件太多,比如:
- 邮件队列
/var/spool/postfix/maildrop/ - 会话文件
/var/lib/php/session/ - 定时任务缓存
/var/spool/cron/ - 临时文件
/tmp下大量小文件 - 容器/应用产生的海量小日志文件
解决方法:删除无用小文件,或调整文件系统预留 inode 数量(但需要重新格式化,不现实),更根本的是从应用层面避免产生海量小文件。
查看各目录大小(排除挂载点)
du -hx --max-depth=1 / | sort -rh
-x 表示不跨文件系统,即只统计当前挂载点的目录,避免进入 /proc、/dev 等伪文件系统或 NFS 挂载点。
你也可以用 ncdu 工具(交互式磁盘分析器),非常直观:ncdu /。
七、监控和告警(化被动为主动)
7.1 磁盘使用率监控脚本
#!/bin/bash
# disk_monitor.sh
THRESHOLD=80
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
if [ $DISK_USAGE -gt $THRESHOLD ]; then
echo "警告:磁盘使用率 ${DISK_USAGE}% 超过阈值 ${THRESHOLD}%"
# 发送告警...
fi
脚本思路:获取根分区使用率(去除%),若超过阈值(如80%)则调用告警接口(邮件、钉钉、企业微信等)。
加入 crontab 每10分钟执行:
*/10 * * * * /root/disk_monitor.sh
生产环境中,建议使用更完善的监控系统,而不是单纯依赖cron脚本,因为脚本本身可能因磁盘满而无法写入日志或发送告警。
7.2 使用Prometheus + Grafana 监控
# alert-rules.yml
- alert: DiskSpaceLow
expr: (1 - node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "磁盘空间不足: {{ $labels.instance }}"
description: "磁盘使用率: {{ $value }}%"
节点导出器(node_exporter)默认采集磁盘使用率、inode、读写IO等指标,配合Prometheus的告警规则(Alertmanager)可实现:
- 磁盘使用率 > 80% 告警(Warning)
- > 90% 告警(Critical)
- 磁盘剩余空间 < 10G 告警
- inode 使用率 > 85% 告警
还可以结合预测算法(如 Prometheus 的预测函数 predict_linear)提前预估磁盘填满时间,实现预测性告警。
八、远程排查技巧(不用跑机房)
服务器在机房,凌晨3点爬起来排查,总不能跑去机房吧。
我用星空组网工具把本地电脑和服务器连起来,直接SSH上去操作:
ssh root@192.168.188.10 df -h du -sh /*
排查、处理、验证,一套流程在家就能搞定。比VPN稳定,也不用担心公司VPN凌晨没人维护。
除了组网工具,还可以搭配堡垒机(JumpServer)或带外管理(iDRAC/iLO)实现远程控制台。对于云服务器,通常有 VNC 或 串口控制台作为备选。远程运维时务必注意网络安全,使用密钥认证、限制登录IP、开启操作审计。
九、预防措施与长期治理
- 日志切割:所有应用日志都配置 logrotate,并且根据重要性设定不同的保留周期(如访问日志保留30天,错误日志保留90天)
- 监控告警:磁盘使用率超过80%就告警,超过90%触发紧急工单,同时监控 inode 使用率
- 定期清理:crontab 定时清理临时文件、过期日志、缓存文件(如每周日凌晨执行清理脚本)
- 容量规划:评估数据增长速度,提前扩容(增加磁盘或 LVM 扩展),或迁移冷数据到对象存储(如 S3/OSS)
- 日志分级与采样:生产环境可减少 debug 日志输出,或使用异步日志缓冲,降低写压力
- 容器环境注意:为每个容器设置存储配额(docker 的
--storage-opt size=10G),避免单个容器写满宿主机
未来趋势:AIOps 智能运维
随着 AI 技术发展,异常检测算法可以自动识别磁盘增长异常模式(如日志突增),提前预警并甚至自动触发 logrotate 或清理操作。同时,云原生场景下,分布式日志系统(如 ELK/Loki)将日志集中存储,节点本地只保留少量缓存,从根本上缓解单机磁盘爆满问题。
总结
磁盘排查三板斧:
df -h # 看哪个分区满了 du -sh /* | sort -rh # 看哪个目录大 find / -type f -size +1G # 找大文件
(通常依次为:df -h 查整体,du -sh /* 查目录,find 查大文件)
常见原因及解决方案汇总表:
| 原因 | 典型路径 | 紧急处理 | 长期根治 |
|---|---|---|---|
| 应用日志未切割 | /var/log/app/* | > logfile 清空 | 配置 logrotate |
| 系统日志积累 | /var/log/messages | 同上 | 调整 rsyslog 策略 |
| 包管理器缓存 | /var/cache/yum | yum clean all | 定期执行清理 |
| Docker 镜像/容器堆积 | /var/lib/docker | docker system prune -f | 设置镜像保留策略 |
| 临时文件残留 | /tmp、/var/tmp | find ... -delete | crontab 定期清理 |
| 已删除文件未释放 | 被进程占用 | 重启进程或清空 fd | 慎用 rm,改用清空 |
最后提醒:线上操作务必先备份关键数据,尤其是在不清除业务数据的前提下。建议先在测试环境模拟演练,确保每一步都心中有数。希望这篇扩展后的记录能真正帮到你,从此不再惧怕磁盘告警。
本文由主机测评网发布,不代表主机测评网立场,转载联系作者并注明出处:https://zhuji.jb51.net/linux/9676.html
