外观
磁盘与 inode
磁盘问题有两层:空间满了和 inode 满了。两者表现相似(都是"写不进去"),但 df -h 正常而 df -i 100% 是后者的唯一线索。
一、先看总量
bash
df -h
df -itext
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% /dataUse% 到 80% 就该处理,85% 是必须处理的线(数据库写日志、临时文件都需要余量)。
根分区单独看
/var/lib/docker、/var/log、/tmp 常在根分区上。业务数据盘用了 50% 但根分区 100%,整机照样起不来。
二、找谁占的
bash
du -h --max-depth=1 /data | sort -hr | head -10text
412G /data
386G /data/mysql
18G /data/logs
4.2G /data/backup
2.1G /data/apptext
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 -20text
10737418240 /data/mysql/ibdata1
4294967296 /var/log/messages
2147483648 /data/app/dump.hprofbash
# 按目录找最大的文件
du -ah /var/log | sort -hr | head -10四、空间没释放(已删除但被占用)
现象:rm 了一个大日志,du 显示没了,但 df 的可用空间没变。
bash
lsof +L1 | head -20
lsof | grep deleted | headtext
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 -itext
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 -ltext
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 vdbtext
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 0bash
mount -a # 按 fstab 挂载所有,验证配置
systemctl daemon-reloadfstab 写错会导致机器起不来
/etc/fstab 里有一条挂不上,系统会停在 emergency mode。
改完务必:
mount -a验证不报错。- 保留一个 root shell 不退出,再重启测试。
救援办法:启动时进 single/emergency,mount -o remount,rw /,改回 fstab。
七、云盘扩容
云控制台把盘从 100G 扩到 200G 后,系统里还是 100G,要自己扩分区和文件系统。
bash
lsblk
growpart /dev/vdb 1text
CHANGED: partition=1 start=2048 old: size=209713152 end=209715199 new: size=419428319 end=419430366bash
# ext4
resize2fs /dev/vdb1
# xfs(只能扩,不能缩)
xfs_growfs /databash
df -h /datatext
Filesystem Size Used Avail Use% Mounted on
/dev/vdb1 200G 412G ... /datagrowpart 失败常见原因:分区不是盘上最后一个。需要先 fdisk 删了重建(数据危险),或换新盘迁移。
八、swap
bash
free -h
swapon --showtext
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 0Redis / 数据库机器不要用 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 mode | fstab 有挂不上的条目 | 注释掉,单用户模式修 |
| 日志目录一直涨 | 没配轮转 | logrotate + 见 日志轮转 |
| 根分区满但业务盘空 | 日志/镜像写在 / | 迁 data-root、日志目录 |