1. 首页 > 服务器系统 > Linux

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-sizemax-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/mysqlshow binary logs;设置 expire_logs_days
Docker日志/var/lib/docker/containersdocker 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 cleanapt 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/yumyum clean all定期执行清理
Docker 镜像/容器堆积/var/lib/dockerdocker system prune -f设置镜像保留策略
临时文件残留/tmp/var/tmpfind ... -deletecrontab 定期清理
已删除文件未释放被进程占用重启进程或清空 fd慎用 rm,改用清空

最后提醒:线上操作务必先备份关键数据,尤其是在不清除业务数据的前提下。建议先在测试环境模拟演练,确保每一步都心中有数。希望这篇扩展后的记录能真正帮到你,从此不再惧怕磁盘告警。

本文由主机测评网发布,不代表主机测评网立场,转载联系作者并注明出处:https://zhuji.jb51.net/linux/9676.html

联系我们

在线咨询:点击这里给我发消息

Q Q:2220678578