周三下午三点多,客户在微信上发来一张截图,是他们官网后台上传商品图时的报错:No space left on device。紧跟着又补了一句:勇哥,服务器硬盘是不是满了?我自己看了下,还剩 30 多个 G 啊。

这家客户是做家居建材的,官网加一个商品管理后台,托管在我们机房一台 R730xd 上,CentOS 7.9,跑了好几年一直挺稳。我第一反应也是磁盘满——这个报错长得太像磁盘满的样子了。

远程上去先敲 df -h:

Filesystem Size Used Avail Use% Mounted on
/dev/sdb1 500G 467G 33G 94% /data

根分区、/tmp、/boot 全扫了一遍,没有一个到 100% 的。既然空间没满,那就是别的问题。我第二个怀疑对象是上传临时目录或者 session 目录被什么塞满了,挨个查了一遍,也没有。

这时候我干了一件现在想起来挺蠢的事:开始用 du 找大文件。du -sh /data/* 一层一层往下钻,半天不出结果——那台机器图片本身就多,全盘 du 一遍要好几分钟。我对着屏幕等输出的时候,客户又发消息来问,好了没?我说快了快了,其实一点头绪都没有。

dmesg 也翻了,没有 IO error,没有坏道报错,磁盘物理故障基本排除。我还远程让客户把 uploads 目录里 20 个 G 的旧视频挪走腾地方——他真挪了,挪完再传图,还是原封不动的报错。电话里我俩都沉默了几秒,我当时心里已经有点发虚,直觉告诉我这压根不是空间的事,可一时就是想不起来还能查什么。

过了好一会儿我才一拍脑袋:df -i 呢?

df -i 一敲出来,答案就摆在那了:

Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sdb1 100% /data

inode 用完了,一个不剩。空间还剩 33G,但文件系统的索引耗光了,任何新建文件的操作都是 errno 28。我让客户白挪的那 20 个 G 视频,就是几个大文件,占的是块空间,释放的 inode 数少得可怜,杯水车薪。

那剩下的问题就变成:谁生了几百万个文件?

查下来是这么回事。客户后台有个功能,商品大图传上去之后会自动切出好几档缩略图,程序只管生成,从来不清理。当初写这套官网的外包公司说过一句“图片都不大,隔段时间手动清一下就行”——结果就是没人清。缩略图按天堆在 /data/www/mall/storage/thumb 下面,我 find 数了一下,光这一个目录就攒了 280 多万个文件,平均一个 1.5K 上下,整个目录 du 出来才 4.3G。所以 df -h 怎么看都是正常的——谁会盯着一个 4.3G 的目录,想到 inode 已经爆了?

清理倒是不复杂,把 30 天以前的缩略图删掉就行,商品图随时可以重新生成。find /data/www/mall/storage/thumb -type f -mtime +30 -delete 这一条命令,跑了差不多四十分钟才完事——文件太多,删也要删一阵。删完再看 df -i,IUse% 掉到 20% 左右,后台传图立刻就好了,连 php-fpm 都不用重启。

收尾我做了三件事。一是给这台机器加了个每周跑的清理脚本,还是删 30 天以前的缩略图,跑完把结果发到邮箱。二是自己在 crontab 里加了一行检查:df -i 用到 85% 就告警,写法很土,df -i 拿 awk 判断一下,超了就发封信,够用就行。三是跟客户讲,让外包公司把“生成缩略图时顺手把过期的删掉”这个逻辑写进程序里,别指望有人记得手动清。

外包公司后来改没改,我不知道,也没去追问。机器这边我自己管住了就行。

这事过去快一个月了,我每次想起来都想笑:df -i 是我入行第一天就会的命令,结果现场愣是排查了快一个小时才想起来用它,中间还让客户白白挪了 20G 视频。客户倒是没说什么,就是后来有次聊天问了我一句:你们运维是不是也有那种,明明会的东西,一着急就想不起来的时候?我说有,还挺多的。