记一次inode数量耗尽导致的生产事故
今天遇到一个挺有趣的场景,公司的线上服务器突然无法访问,当我尝试重新部署项目解决问题的时候却提示我说空间不足。这就很耐人寻味了,磁盘空间显示还剩几十个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 number
是6556243
。我们可以通过命令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个月都会遇到点刺激的事故。这一两年下来算是习惯了,可能这也是后端/运维工作的常态吧。