Skip to content

磁盘与 inode ​

磁盘问题有两层:空间满了和 inode 满了。两者表现相似(都是"写不进去"),但 df -h 正常而 df -i 100% 是后者的唯一线索。

一、先看总量 ​

bash
df -h
df -i
text
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        40G   32G  6.2G  84% /
/dev/vdb        500G  412G   63G  87% /data
tmpfs           3.9G     0  3.9G   0% /dev/shm

Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/vda1      2621440 412883 2208557   16% /
/dev/vdb      32768000 188421 32579579    1% /data

Use% 到 80% 就该处理,85% 是必须处理的线(数据库写日志、临时文件都需要余量)。

根分区单独看

/var/lib/docker、/var/log、/tmp 常在根分区上。业务数据盘用了 50% 但根分区 100%,整机照样起不来。

二、找谁占的 ​

bash
du -h --max-depth=1 /data | sort -hr | head -10
text
412G	/data
386G	/data/mysql
18G	/data/logs
4.2G	/data/backup
2.1G	/data/app
text
du -sh /data/* 2>/dev/null | sort -h | tail -10
du -h --max-depth=2 /var | sort -hr | head -20

-x 不跨文件系统(重要,避免统计到挂载点下面):

bash
du -xh --max-depth=1 / | sort -hr | head -10

排除某些目录:

bash
du -h --max-depth=1 --exclude='./backup' /data | sort -hr

三、找大文件 ​

bash
find / -xdev -type f -size +1G -printf '%10s %p\n' 2>/dev/null | sort -rn | head -20
text
10737418240 /data/mysql/ibdata1
 4294967296 /var/log/messages
 2147483648 /data/app/dump.hprof
bash
# 按目录找最大的文件
du -ah /var/log | sort -hr | head -10

四、空间没释放(已删除但被占用) ​

现象:rm 了一个大日志,du 显示没了,但 df 的可用空间没变。

bash
lsof +L1 | head -20
lsof | grep deleted | head
text
COMMAND   PID USER   FD   TYPE DEVICE  SIZE/OFF NLINK     NODE NAME
java    31882  app    3w   REG  fd01h 42949672960     0 1832441 /data/app/app.log (deleted)

NLINK 0 + (deleted):文件被删了,但进程还开着文件句柄,内核不回收。

处理:

bash
# 最温和:清空内容(进程继续写,空间立刻回收)
truncate -s 0 /proc/31882/fd/3

# 或者重启那个进程
systemctl restart app

不要直接 kill -9 了事

先确认这个进程是什么。生产上因为 kill -9 导致数据没 flush、事务未提交的事故,比磁盘满本身更严重。

正确顺序:truncate 释放空间 → 排查为什么日志没轮转 → 修 logrotate。

五、inode 耗尽 ​

bash
df -i
text
Filesystem      Inodes   IUsed    IFree IUse% Mounted on
/dev/vda1      2621440 2621440        0  100% /

空间还有几百 G,但创建任何新文件都报 No space left on device。

排查是谁产生的小文件:

bash
# 每个一级目录的 inode 数
for d in /*; do echo "$(find "$d" -xdev -type f 2>/dev/null | wc -l) $d"; done | sort -rn | head

# 常见元凶:session 文件、缓存、日志分片、邮件队列
find /var/spool -type f | wc -l
find /var/lib/php/sessions -type f | wc -l
text
2184933 /var
  38210 /usr
    991 /etc

/var 里 218 万个文件,再看下一层:

bash
du -h --max-depth=2 /var | sort -hr | head
find /var/spool/postfix -type f | wc -l

清理后 inode 才会释放。find -delete 比 rm -rf * 更稳(参数列表不会超长):

bash
find /var/spool/postfix/deferred -type f -mtime +7 -delete

六、挂载与 fstab ​

bash
lsblk
blkid
mount | grep vdb
text
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
vda    254:0    0   40G  0 disk
└─vda1 254:1    0   40G  0 part /
vdb    254:16   0  500G  0 disk
└─vdb1 254:17   0  500G  0 part /data

/dev/vdb1: UUID="8f2c1e9a-7b3d-4c5e-8a0b-2c4d6e8f0a1b" BLOCK_SIZE="4096" TYPE="xfs" PARTUUID="..."

/etc/fstab 用 UUID 而不是设备名(云盘设备名重启后可能变):

ini
UUID=8f2c1e9a-7b3d-4c5e-8a0b-2c4d6e8f0a1b  /data  xfs  defaults,noatime  0 0
bash
mount -a          # 按 fstab 挂载所有,验证配置
systemctl daemon-reload

fstab 写错会导致机器起不来

/etc/fstab 里有一条挂不上,系统会停在 emergency mode。

改完务必:

  1. mount -a 验证不报错。
  2. 保留一个 root shell 不退出,再重启测试。

救援办法:启动时进 single/emergency,mount -o remount,rw /,改回 fstab。

七、云盘扩容 ​

云控制台把盘从 100G 扩到 200G 后,系统里还是 100G,要自己扩分区和文件系统。

bash
lsblk
growpart /dev/vdb 1
text
CHANGED: partition=1 start=2048 old: size=209713152 end=209715199 new: size=419428319 end=419430366
bash
# ext4
resize2fs /dev/vdb1

# xfs(只能扩,不能缩)
xfs_growfs /data
bash
df -h /data
text
Filesystem      Size  Used Avail Use% Mounted on
/dev/vdb1       200G  412G  ...    /data

growpart 失败常见原因:分区不是盘上最后一个。需要先 fdisk 删了重建(数据危险),或换新盘迁移。

八、swap ​

bash
free -h
swapon --show
text
               total        used        free      shared  buff/cache   available
Mem:            15Gi        13Gi       512Mi       1.0Gi       1.8Gi       900Mi
Swap:          4.0Gi       1.2Gi       2.8Gi

NAME      TYPE      SIZE USED PRIO
/swapfile file        4G 1.2G   -2

临时加 swap:

bash
fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

永久:

ini
/swapfile  none  swap  sw  0 0

Redis / 数据库机器不要用 swap

内存换出会让延迟从微秒变成毫秒。生产上给这类服务设 vm.swappiness=1,并考虑关闭 swap。容器场景还要在 docker run 时用 --memory-swap 等于 --memory 禁用。

九、踩过的坑 ​

现象根因处置
df 有空间但写不进去inode 用尽df -i,清小文件
rm 后空间不降进程持有句柄lsof +L1,truncate /proc/PID/fd/N
du 和 df 差很多有已删除未释放文件,或有挂载点被覆盖lsof +L1,mount | grep
扩容后 df 不变只扩了云盘,没扩分区/文件系统growpart + resize2fs/xfs_growfs
重启进 emergency modefstab 有挂不上的条目注释掉,单用户模式修
日志目录一直涨没配轮转logrotate + 见 日志轮转
根分区满但业务盘空日志/镜像写在 /迁 data-root、日志目录