← 回目录
21 Week 05 · 磁盘与软件

磁盘满了怎么办

运维最常接到的报障之一。今天除了标准流程,还有两个能明显拉开差距的答案——大部分候选人答不出来。

标准三步

先掌握主线
① 定位是哪个分区满了
$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/rl-root    62G   59G  3.0G  96% /
/dev/sda1            1014M  247M  768M   25% /boot
     ↑ 根分区 96%,就是它
② 逐层往下找大目录
$ sudo du -sh /* 2>/dev/null | sort -rh | head
 32G  /var
 12G  /usr
  4G  /home

# 找到 /var 最大,再往下钻一层
$ sudo du -sh /var/* 2>/dev/null | sort -rh | head
 28G  /var/log
     ↑ 一层层缩小范围,直到定位到具体文件

$ sudo du -sh /var/log/* | sort -rh | head -5
③ 处理
# 清理老日志(Day 05 的 -mtime +7)
$ sudo find /var/log -name "*.log" -mtime +7 -delete

# 清理 journal(Day 13 学的)
$ sudo journalctl --vacuum-time=7d

# 清理 dnf 缓存
$ sudo dnf clean all
du 和 df 的分工

df 看分区级别(还剩多少),du 看目录级别(谁占的)。先 df 定位分区,再 du 找元凶——顺序反了会在无关分区上瞎找。

加分答案一:lsof | grep deleted

这条能拉开差距

现象:df 说磁盘满了,但 du 一层层加起来对不上——差好几十 G 找不到。

为什么会这样
原因
有人删了一个大日志文件,但写这个文件的进程还开着它。文件名没了(du 看不到),但磁盘空间没释放df still 算着)。
典型场景
「日志太大我 rm 了,怎么磁盘还是满的?」——因为 nginx / java 进程还占着那个已删除的文件句柄。
怎么找
sudo lsof | grep deleted
怎么解决
重启那个进程,句柄释放,空间立刻回来。或者用 > /proc/PID/fd/N 清空它。
实际操作
$ sudo lsof | grep deleted
nginx  3412  nginx  6w  REG  253,0  21474836480  /var/log/nginx/access.log (deleted)
                                     ↑ 20G 的已删除文件还占着

# 方法一:重启服务(最简单)
$ sudo systemctl restart nginx

# 方法二:不重启,直接清空那个文件句柄
$ sudo truncate -s 0 /proc/3412/fd/6

$ df -h    # 空间回来了
顺带一个正确姿势

清空一个正在被写入的日志,不要用 rm,要用 truncate 或者重定向:

sudo truncate -s 0 /var/log/nginx/access.log

或者 sudo sh -c '> /var/log/nginx/access.log'

这样文件还在、句柄还在、空间立刻释放,服务也不用重启。

加分答案二:inode 耗尽

另一种"磁盘满"

现象:df -h 显示还有空间,但就是写不进去,报 No space left on device

查 inode
$ df -i
Filesystem           Inodes  IUsed IFree IUse% Mounted on
/dev/mapper/rl-root  3.9M    3.9M   1.2K  100% /
                                           ↑ inode 用光了
inode 是什么
概念
每个文件都要占一个 inode(存元数据的槽位)。格式化时数量就定死了。
什么时候会爆
海量小文件——session 文件、缓存碎片、邮件队列。空间没用完,但槽位用光了。
怎么找
sudo find /var -xdev -type f | cut -d/ -f1-4 | sort | uniq -c | sort -rn | head——按目录统计文件数量而不是大小。
这两条为什么值钱

「磁盘满了怎么查」——大部分人答到 df + du 就没了。

你能接着说出「如果 df 和 du 对不上,查 lsof deleted」和「如果空间够但写不进去,查 df -i 看 inode」,面试官立刻知道你真处理过线上磁盘告警。

其他常用

看磁盘结构
$ lsblk                    # 磁盘、分区、挂载点的树状图
NAME        MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda           8:0    0  64G  0 disk
├─sda1        8:1    0   1G  0 part /boot
└─sda2        8:2    0  63G  0 part
  └─rl-root 253:0    0  62G  0 lvm  /

$ df -hT                   # -T 显示文件系统类型(xfs/ext4)
$ du -sh /var/log          # 单个目录总大小
$ du -h --max-depth=1 /var # 只看一层,等价于 du -sh /var/*
-xdev 参数

dufind 加上 -xdev(或 -x)表示不跨越文件系统边界

否则你在 / 上找大文件,会把挂载在下面的其他分区、网络存储也算进去,结果对不上还浪费时间

今天的面试点

「服务器磁盘满了,你怎么排查?」

主线:「df -h 先定位哪个分区 → du -sh /* | sort -rh 逐层往下找大目录 → 找到具体文件后清理,一般是日志。」

加分一:「如果 df 显示满了但 du 加起来对不上,那多半是有进程占着已删除的文件lsof | grep deleted 能查到,重启那个服务空间就回来了。」

加分二:「还有一种情况是空间够但 inode 用完了df -i 能看出来,通常是海量小文件导致的。」

「日志文件太大,能直接 rm 吗?」

不建议。如果服务还在写它,rm 之后空间不会释放,还得重启服务。」

「我一般用 truncate -s 0 清空——文件还在、句柄还在、空间立刻释放,服务不用重启。长期方案是配 logrotate(第 29 天)。」

今天的练习

敲完再走 · 约 15 分钟
  • df -hdf -i 各看一次,理解两者查的是不同的东西
  • lsblk,画出你这台虚拟机的磁盘结构(注意 rl-root 那个 lvm,后天要用)
  • 逐层往下钻:sudo du -sh /* | sort -rh | head → 挑最大的再钻一层 → 再一层
  • 重点实验:造一个 500M 的大文件 sudo dd if=/dev/zero of=/var/log/big.log bs=1M count=500,用 df -h 看空间变化,再 rm 掉看空间是否立刻回来
  • 再做一次 deleted 实验sudo tail -f /var/log/big2.log & 挂着 → 另开窗口 rm 掉它 → df -h 看空间没回来 → sudo lsof | grep deleted 找到它 → kill 掉 tail → 空间回来
  • sudo lsof | grep deleted | head,看你机器上有没有这种情况
明天预告

Day 22 给虚拟机加一块新硬盘,走一遍分区 → 格式化 → 挂载 → 写 fstab 的完整流程。

这是最接近真实工作的练习,也是 /etc/fstab 写错会导致系统开不了机的那一天。