今天遇到一个挺有趣的场景,公司的线上服务器突然无法访问,当我尝试重新部署项目解决问题的时候却提示我说空间不足。这就很耐人寻味了,磁盘空间显示还剩几十个G,一查发现原来是inode的问题,这篇文章简单记录一下。

Linux系统的inode指标

Linux系统里面有一个inode的概念,大概是这样一个意思

An inode is a data structure that keeps track of all the files and directories within a Linux or UNIX-based filesystem. So, every file and directory in a filesystem is allocated an inode, which is identified by an integer known as “inode number”. These unique identifiers store metadata about each file and directory.

简单来说就是,在Linux或者类Unix的文件系统里面,所有的文件/目录都会被分配一个inode number,这是一个唯一的编号,且数量是有限的。我们可以通过ls -i来查看对应文件的inode number。比如这样

> ls -i apiclient_key.pem
6556243 apiclient_key.pem

表明apiclient_key.pem这个文件的inode number6556243。我们可以通过命令df -i查看当前系统里inode总量

> df -ih

Filesystem      Inodes   IUsed   IFree IUse% Mounted on
udev           1975880     418 1975462    1% /dev
tmpfs          1982935     626 1982309    1% /run
/dev/vda1      9830400 6873397 2957003   70% /

inode“超标”导致的“空间不足”

对阿里云服务器来说,一般硬盘的存储设备都是/dev/vdax,我这台服务器刚好是/dev/vda1。从上面的结果可知,该文件系统的inodes总容量是9830400,已经使用了6873397,还剩余2957003。讲得再生动一点就是,这台服务器一共可以创建9830400个文件/目录,现在已经有6873397个了,接下来最多也只能创建2957003个文件/目录。如果数量超出之后,再尝试创建文件的时候系统会报错

No space left on device or running out of Inodes.

第一次遇到这个错的时候,笔者也是吓懵了,毕竟这辈子从来没有见到过,而且当时线上的服务完全停滞,需要紧急修复。明明磁盘还有几十G的盈余,为何会No space left on device。当时我的服务器大概都成这个鬼样了吧(这还是删除大量文件之后)

> df -ih
Filesystem      Inodes   IUsed   IFree IUse% Mounted on
udev             1.9M   418  1.9M    1% /dev
tmpfs            1.9M   626  1.9M    1% /run
/dev/vda1        9.4M  9.3M  108K   99% /
....

系统运行有2年时间了,只是盯着磁盘空间看,没有留意到inode数量也会造成“空间不足”,也算是一点小经验了。幸好当时笔者距离家不远,急忙赶回家修复不至于耽误太长的时间。网上找到这个脚本,可以查找当前目录下文件数量最多的子目录,这是最后在Rails项目目录下的tmp/目录里面运行的结果

> sudo find shared -xdev -type f | cut -d "/" -f 2 | sort | uniq -c | sort -nr

9045071 cache
      8 videos
      2 pids

可见cache目录里面有太多的文件。估计是我使用模板系统的时候开启了缓存导致的。从文件落地的情况来看应该是使用了类似Rails的Fragment Caching。模板以持久化的方式缓存了,且没有定时清理,运行时间太长,导致了tmp/cache目录下的缓存模板越来越多。最终把操作系统的inode number给撑爆了。

解决方案其实挺简单的。可以手动删除一下

rm -rf tmp/cache/*

官方的做法则是通过脚本

> Rails.cache.clear

作用是一样的,只是清理了tmp/cache目录下的所有缓存文件。最大的问题是,缓存文件多的时候,这个过程会比较慢,占用系统资源导致服务器卡顿。建议定期清理,不用一次过清理干净,也可以只清理那些失效很长时间的缓存模板文件。

总结

第一次遇到这种场景的时候还是挺吓人的,似乎每1 ~ 2个月都会遇到点刺激的事故。这一两年下来算是习惯了,可能这也是后端/运维工作的常态吧。