凌晨1点,告警群弹出一条:生产服务器磁盘告警——"No space left on device"。你从床上弹起来,习惯性敲下df -h,却发现根分区还有20GB可用。不是磁盘写满?那为什么报空间不足?
再敲一行df -i,真相大白:IUse%显示100%,inode耗尽了。每个文件都要占用一个inode,大量小文件(session、缓存碎片、cron日志)早已悄无声息地填满了inode表——磁盘有空间,但文件系统拿不出新的inode来创建文件。
核心结论:df -h看容量,df -i看inode。两个指标都要监控,磁盘空闲不等于能写入。
一、现象确认:空间和inode是两个维度
1.1 两行命令锁定根因
df -h / 看磁盘空间使用率 — 还剩20G,正常。
df -i / 看inode使用率 — 100%,问题确认。
两者的差异就是排查方向:磁盘空间够但inode满了,说明存在某个目录下堆积了海量小文件。一个1字节的空文件和一个1GB的电影文件,都消耗1个inode。当几百个字节的session文件、几KB的缓存碎片以百万计堆积时,inode会比磁盘空间先耗尽。
1.2 常见受害者场景
PHP Session目录(/var/lib/php/sessions)— 以sess_开头的文件堆积几百万个。
Cron邮件队列(/var/spool/postfix/maildrop)— crond任务有输出却未配置MAILTO,邮件排队不清理。
Docker overlay2(/var/lib/docker/overlay2)— 镜像层、容器层碎片化,小文件数量惊人。
前端构建产物 — node_modules/.cache、npm缓存、webpack临时文件。
二、原理拆解:inode到底是什么
2.1 inode的职责
inode(索引节点)是文件系统用于存储文件元数据的结构,每个文件/目录/符号链接都消耗一个inode。它记录了文件大小、权限、所有者、时间戳、数据块指针——但不包含文件名,文件名存在目录项中。
文件系统格式化时inode表的大小就已固定,ext4默认每16KB磁盘空间分配一个inode。当你的磁盘主要存放大文件(视频、数据库、镜像),inode绰绰有余;一旦场景变成海量小文件(缓存、日志、session),磁盘空间还剩大半时inode就已耗尽。
三、三线定位:快速找到inode消耗重灾区
3.1 第一线:全局扫描inode分布
用du命令的--inodes参数按目录统计inode消耗量:
du --inodes -d 3 / | sort -rn | head -20
这条命令从根目录递归3层,统计每个子目录的inode数量,倒序排列取前20。几秒内就能锁定inode消耗最大的目录——通常是/var、/tmp或/home下的某个子目录。
3.2 第二线:逐层下钻定位
锁定目标目录后,逐步缩小排查范围:
du --inodes -d 1 /var/lib/ | sort -rn
一层层下钻,直到找到具体的"罪魁祸首"子目录。不要用ls -lR | wc -l来统计文件数——这个命令本身会消耗大量CPU且结果不精确。
3.3 第三线:确认文件数量和特征
进入目标目录后验证:
ls -f | wc -l — 快速计数(-f不排序,千万级文件下也能快速返回)。
find . -type f -printf '%T+ %p\n' | head -20 — 查看最近创建的文件,判断是哪种应用程序在持续生成。
ls -lt | head -20 — 查看最新文件的修改时间,确认是持续增长还是历史堆积。
四、紧急清理:按场景对症下药
4.1 PHP Session目录清理
rm -f /var/lib/php/sessions/sess_*
直接删——session文件丢失只会让用户重新登录,不影响数据安全。注意:百万级文件时rm可能因参数列表过长报错。改用:
find /var/lib/php/sessions/ -type f -name 'sess_*' -delete
4.2 过期日志清理
find /var/log -type f -name '*.log' -mtime +30 -delete
删除30天前的日志文件。执行前先用find ... -mtime +30 | wc -l确认影响面。
4.3 Docker资源回收
docker system prune -a -f --volumes
一键清理停止的容器、未使用的网络、悬空镜像和未使用的卷。Docker overlay2目录下的inode消耗经常在百万级别。
4.4 大目录高效删除技巧
百万级文件用rm可能卡死。更高效的方式:
mkdir /tmp/empty && rsync -a --delete /tmp/empty/ /path/to/purge/
rsync同步空目录到目标目录,利用--delete机制实现高速清空。或者直接删父目录再重建:
rm -rf /path/to/purge && mkdir -p /path/to/purge && chown --reference=/backup/ref /path/to/purge
五、短期预防:堵住源头不让inode再次跑满
5.1 logrotate强制压缩轮转
在/etc/logrotate.d/下的应用日志配置中加上:
maxsize 100M
rotate 5
compress
delaycompress
核心参数解读:maxsize限制单文件大小、rotate控制保留份数、compress开启gzip压缩——三个参数协同将日志文件数控制在固定范围内。
5.2 PHP Session GC参数调小
修改php.ini:
session.gc_maxlifetime = 1440 — 24分钟过期自动清理。
session.gc_probability = 1 / session.gc_divisor = 100 — 每次请求1%概率触发GC。
高并发站点建议将gc_probability/gc_divisor设为1/1000以降低GC开销,配合cron定时清理:
find /var/lib/php/sessions -type f -cmin +1440 -delete
5.3 tmpwatch / systemd-tmpfiles 定期清理
tmpwatch --mtime 240 /tmp — 清理/tmp下10天前修改的文件。
或用systemd-tmpfiles(更现代):在/etc/tmpfiles.d/下创建配置:
d /tmp 1777 root root 10d
系统每24小时自动清理/tmp中超过10天的临时文件。
六、长期方案:文件系统选型与参数调优
6.1 ext4加大inode比例
格式化ext4时通过-i参数控制inode分配密度:
mkfs.ext4 -i 8192 /dev/sdb1 — 每8KB分配一个inode(默认16KB),inode数量翻倍。
mkfs.ext4 -N 5000000 /dev/sdb1 — 直接指定inode总数。
注意:-i参数设太大会浪费空间、影响fsck速度。建议先分析现有数据目录的平均文件大小,再决定inode密度。
6.2 XFS动态inode分配
XFS文件系统采用动态inode分配机制——创建文件时才分配inode,没有固定上限。只要磁盘有空间,就能继续创建文件。对于海量小文件场景(邮件服务器、对象存储、容器宿主机),XFS是比ext4更优的选择。
迁移命令:备份数据 → mkfs.xfs /dev/sdb1 → 恢复数据。XFS还支持在线扩容(xfs_growfs),但不支持缩容,规划时需注意。
七、ext4 vs XFS 关键对比
ext4
inode分配:格式化时固定,不可扩展
小文件场景:需手动调整-i参数
百万级文件删除:rm较慢,需特殊处理
fsck速度:较快,依赖inode数量
缩容支持:支持(resize2fs)
适用场景:通用、兼容性好、需要缩容
XFS
inode分配:动态分配,无上限
小文件场景:开箱即用,不会inode耗尽
百万级文件删除:rm略快,但同样建议用rsync技巧
fsck速度:极快,日志式恢复
缩容支持:不支持
适用场景:海量小文件、大容量、高性能IO
选择建议:如果服务器上跑的是容器、邮件队列、文件存储类服务,直接选XFS,一劳永逸解决inode问题。如果只是Web应用偶尔触发,ext4配合监控即可。
八、运维检查清单与监控告警
日常巡检:
① 监控系统同时采集df -h和df -i两个指标,任一超过85%触发预警。
② 设置cron每周执行du --inodes -d 2 /var | sort -rn | head -10输出到日志,长期跟踪趋势。
③ /var/lib/php/sessions、/var/spool/postfix、/var/lib/docker 三个目录列入重点观察清单。
告警阈值:
④ Inode使用率 > 85%:黄色预警,通知运维排查趋势。
⑤ Inode使用率 > 95%:红色告警,立即执行清理流程。
⑥ Inode使用率增速 > 5%/小时:紧急告警,可能有程序异常生成文件(死循环写日志、session生成风暴)。
应急SOP:
⑦ 确认df -i → 定位目录du --inodes → 清理/删除 → 确认df -i回落 → 复盘加监控。
传播金句
磁盘有空间 ≠ 能写入。inode才是决定你能创建多少个文件的真正上限。
凌晨三点的inode告警,往往来自三个月前忘加logrotate的那行配置。
df -h看的是地图上的土地面积,df -i看的是你还能盖多少栋楼。
如果你也曾在半夜被"No space left on device"惊醒,欢迎转发这篇文章给你的同事——让他们也知道,磁盘监控要两条线一起看。