服务器磁盘满了要如何快速解决


服务器磁盘满了要如何快速解决

最近排查和解决了一个磁盘快满的生产问题。跟大家分享一下思路哈。

  1. 查看磁盘使用率、容量
  2. 分析磁盘占用根源
  3. 临时解决(先降磁盘使用率,恢复系统正常)
  4. 从根源优化,防止问题复发
  5. 复盘(避免重复踩坑)

1.查看磁盘使用率、使用量,定位始作俑者

1.1 使用命令查看磁盘使用率

如果磁盘满了,我们首先要明确哪个分区满了、哪些文件或者目录占了大部分空间。

一般用这个命令:

# 查看所有挂载分区的磁盘使用率(重点看Use%列)
df -h

当然,如果df -h显示不全,用df -hT查看分区类型和挂载点。

一般是这么输出的:

Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1       40G   35G  2.8G  92% /          # 根分区使用率92%,重点排查
/dev/vdb1      200G   50G  140G  26% /data

我们一般重点关注 Mounted on(挂载点)和Use%(使用率),比如这里的92% ,就要重点排查。

1.2 定位该分区下占用空间最大的目录 / 文件

我们针对超标分区(比如/),从根目录开始逐层排查:

# 进入超标分区的挂载点(比如根分区)
cd /
# 查看当前目录下各子目录的大小(-h人性化显示,-s汇总,--max-depth=1只看一级目录)
du -h --max-depth=1

这样我们就可以看到示例:

18G    /var
10G    /usr
5G     /home
1.5G   /opt

比如上面这个例子,可以看到/var目录占了 18G,是重点排查对象,继续深入转开:

# 进入/var目录,查看二级目录大小
cd /var
du -h --max-depth=1
# 若发现/var/log占比最大,继续深入
cd /var/log
du -h --max-depth=1

1.3 定位大文件

我们要定位大文件,(尤其是 Java 相关的日志 或者缓存)

如果目录排查中发现某个目录占比极高,可直接查找该目录下的大文件:

# 查找/var目录下大于100M的文件(按大小排序,方便定位最大文件)
find /var -type f -size +100M -exec ls -lh {} \; | sort -rh -k5

2. 分析磁盘占用的根源

定位到大文件或者目录后,我们就要分析问题产生的根源啦。

2.1 其实最常见的,就是日志无限制写入。

比如目录/logs/下,有超大日志文件(如app.logerror.log达几十 G)

常见原因:

  • 日志级别配置为DEBUG
  • 系统出现异常(如循环报错、接口频繁调用),日志疯狂输出;
  • 第三方组件日志(如Tomcat/Nginx/MySQL 日志)未清理

2.2 Java 应用产生的临时文件 / 缓存未清理

这些现象也比较多

  • tmp/目录下有大量 Java 进程生成的临时文件(如tomcat-tmp、jdk-tmp);
  • 应用的缓存目录(如 Redis 持久化文件、Elasticsearch 数据文件、本地缓存文件)持续增大;
  • JVM 的堆转储文件(*.hprof):应用 OOM 时生成的堆快照,单个文件可达数 G。

原因

  • 代码未正确清理临时文件(如File.createTempFile后未删除);
  • OOM 后自动生成的堆转储文件未及时清理;
  • 缓存策略不合理,缓存文件只增不减。

当然,其实还有一些其他原因,比如磁盘挂载错误、僵尸进程占用的临时文件(lsof | grep deleted可查)

3. 临时解决(先降磁盘使用率,恢复系统正常)

我们找到磁盘占用大头的根源后,先做临时处理,确保磁盘使用率降到 80% 以下,避免系统因磁盘满导致服务不可用

  • 如果是大日志文件,可以先备份(如果需要),然后清空或者直接删除:
find /var/log/app/ -name "app.log" -size +500M -exec rm -f {} \;
  • 如果是未释放的删除文件

如果发现lsof | grep deleted有大量已删除但未释放的文件(比如 Java 进程占用的日志文件):

# 查找已删除但未释放的大文件(列进程ID、文件大小、文件路径)
lsof | grep deleted | awk '{print $2, $7, $9}' | sort -rh -k2
  • 清理临时文件 / 堆转储文件
# 删除tmp目录下7天前的临时文件
find /tmp/ -name "*-tmp-*" -mtime +7 -delete

如果一时半会找不到要删除的文件的话,那就要先紧急扩容,比如临时挂载临时磁盘或扩容。

4. 从根源优化,防止问题复发

我们临时解决了磁盘使用率之后,就要从根源来优化啦,防止问题复发哈。

4.1 日志层面

如果是日志导致的问题,可以

  • 调整日志级别
  • 配置日志清理脚本

4.2 代码、系统层面

  • 排查死循环等bug:修复bug
  • 清理临时文件:代码中生成临时文件后,通过finally块确保删除;
  • 限制堆转储文件:JVM 参数中配置-XX:HeapDumpPath=/data/heapdump/(指定到大容量分区),并限制只在必要时生成
  • 监控文件写入:在代码中监控关键目录的大小,超过阈值时告警

5. 复盘(避免重复踩坑)

处理完成后之后呢,一般需要复盘:

  • 记录本次磁盘满的根因;
  • 检查所有 Java 应用的日志配置,确保都开启了滚动和清理;
  • 补充监控指标:新增日志文件大小临时目录大小堆转储文件生成的监控;
  • 完善应急预案:将本次排查步骤整理成文档,纳入团队故障处理手册

最近我们那个告警问题,就是一个日志,递归遍历节点的,以前的开发者排查bug的时候,打印的日志忘记删掉,导致日志文件膨胀,最后磁盘率飙升的。

我当时找到因为定位到后,先备份日志文件,然后删掉日志文件,释放磁盘空间,最后发版代码,把疯狂输出日志的代码干掉。好啦,本文就到啦,希望大家看完有帮助~~


文章作者: 威@猫
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 威@猫 !
评论
  目录