Linux 记一次 inode 数量耗尽导致的生产事故

lanzhiheng · 2022年12月10日 · 最后由 as181920 回复于 2023年01月25日 · 956 次阅读

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

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 个月都会遇到点刺激的事故。这一两年下来算是习惯了,可能这也是后端/运维工作的常态吧。

这确实有点坑 不知道 windows 是不是也有这个文件上限的限制

msl12 回复

😂 应该没有吧。

俺们用 docker 部署就不怎么担心这个问题,每次部署都是个新的容器,缓存文件会被清掉。。。缺点是部署时间较长

lanzhiheng 回复

@lanzhiheng @msl12

文件系统都有 inode,都会有上限

spike76 回复

docker 部署时间会比较长?我理解就是创建容器就好?

即使用上了 Redis 作为 KV Store,仍然建议使用 config.cache_store = :mem_cache_store 配合 MEMCACHE_SERVERS 环境变量部署 memcached 服务。

activesupport-cache-memcachestore

https://github.com/dao42/rails-template/blob/master/files/config/deploy.rb#L58

这是 rails-template 上的发布脚本,看看是不是 bootsnap 的锅。

xinyifly 回复

😬 提醒我了,原来我们一直用了 file_store 也难怪会把磁盘撑爆炸。我们现在还是单机,我是打算先使用现用的 Redis,等我后面基础架构更稳定一些,我再换成您说的 mem_cache_store。因为这东西肯定也要买第三方的比如阿里云,现在多一个第三方的服务对我们来说也是种负担。😂

lyfi2003 回复
>  bootsnap/ -xdev -type f | cut -d "/" -f 2 | uniq -c | sort -nr
 261655 compile-cache
      1 load-path-cache

看着还好,相比起来不算什么。准备把缓存引擎换成是 redis,然后部署脚本多加一个删除缓存的指令Rails.cache.clear 应该能缓解不少。

lanzhiheng 回复

这里要考虑的是缓存服务器在内存满了的时候要用什么过期策略。如果 kv 数据和缓存都用同一个 redis 的话,可能同一个过期策略无法满足两种需求,例如一个留存很久但有用的 kv 数据被挤掉的。所以上面推荐另外开个 memcache 服务。

另一种做法是 redis 只用来做缓存,不存持久数据。

Rei 回复

😂 了解,这个我权衡一下哈。我们现在的体量,其实我感觉直接用 memory_cache 都差不多了。Redis 就继续用来存 kv 数据。我是打算等上了 k8s 之后再考虑用外部的缓存服务。

lanzhiheng 回复

还得构建镜像,推送镜像 😁 。我们用 github action + AWS ECS, 部署时间通常要几分钟的。暂时没空优化,不知道有没有老哥有这方面的优化经验分享一下😀

spike76 回复

😂 没有啊。回头一起探讨一下?我们刚准备上呢。我也是一头雾水。你的镜像会不会有优化的空间?😂 有时间优化搞个轻量级的镜像可能能省下不少网络传输时间呢。

lanzhiheng 回复

有空交流啊,微信发你邮箱勒😀

我其实已经找到了部署问题,就是没有充分利用 github action 的缓存,导致构建镜像太慢,暂时没时间去实验。

很早之前我就用过 alpine 的版本来做基础镜像,最终构建出来的镜像能比基于标准版的镜像小接近一半。不过由于 cto 的轻微反对,加习惯使用 ubuntu 了,就又切回去了

spike76 回复

😂 ubuntu 省事。Github action 缓存比较折腾。不过到了一定地步肯定要弄了。我们现在都自建 Gitlab 了。主要是 Github 之前有段时间网络不稳定,小伙伴建议用 Gitee。我......

lanzhiheng 回复

也不是一定要购买云服务,一些基础的软件 redis/pg/mq 等自建还是蛮稳定的,看业务要求到什么程度。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号