记一次由于磁盘 Inode 用满导致的故障

背景#

在一台 ubuntu 服务器上运行了多个 laravel 项目

发现问题#

昨天早上有客户提醒服务不可用。排查后发现是磁盘满了(100G)。删除掉 40G 的备份文件后,服务恢复正常。

但是今天早上,又有很多客户反应服务挂掉了。

查看日志,发现有大量的 failed to open stream: No space left on device 的错误。使用 df -h 查看,磁盘明明还有 40G 空间,按道理不应该出现这个错误。

查找问题#

磁盘空间明明还有,但提示空间不足。遂使用 df -ih 查看了一下 inode 的使用情况。

~ df -ih
Filesystem     Inodes IUsed IFree IUse% Mounted on
udev             490K   437  490K    1% /dev
tmpfs            494K   944  494K    1% /run
/dev/vda1        2.5M  102K  2.5M    4% /
tmpfs            494K     1  494K    1% /dev/shm
tmpfs            494K     2  494K    1% /run/lock
tmpfs            494K    16  494K    1% /sys/fs/cgroup
/dev/vdb1        6.3M  6.3M  1.3M. 100% /mnt/vdb

发现 inode 已经用满了,从而导致系统无法创建文件。以至于系统抛出 No space left on device 错误。

inode 是什么?

理解 inode,要从文件储存说起。

文件储存在硬盘上,硬盘的最小存储单位叫做 "扇区"(Sector)。每个扇区储存 512 字节(相当于 0.5KB)。

操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个 "块"(block)。这种由多个扇区组成的 "块",是文件存取的最小单位。"块" 的大小,最常见的是 4KB,即连续八个 sector 组成一个 block。

文件数据都储存在 "块" 中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做 inode,中文译名为 "索引节点"。

每一个文件都有对应的 inode,里面包含了与该文件有关的一些信息。

引用自:http://www.ruanyifeng.com/blog/2011/12/ino...

因此,为题就是磁盘的 block 空间还有剩余,但是 inode 空间用完,无法继续创建新文件。

分析问题#

在运行的几个 laravel 项目中,有 2 个访问量很大,而且有写缓存(CACHE_DRIVER=file)。

进入到 laravel 项目的 storeage/framework/cache/data 目录下,发现存在大量的文件夹,里面存储的是大量的小文件(一个文件只有几 KB)。

这些大量的小文件并没有占用多少 block 空间,却吧 inode 空间占满了。

解决问题#

  1. 删除项目的 Cache 文件
    停止 nginx、 php-fpm,进入 data 目录,执行:rm -rf ./*
    然后悲剧了,系统卡死, 10 分钟、半小时、1 小时...,没办法,只能先清理一部分出来,晚上再删。

  2. 切换缓存到 redis(阿里云的云服务)

  3. 搞一个脚本,每晚定时清理。

  4. 挂在新的磁盘,软连接到 cache 目录,以缓解单块磁盘的 inode 空间不足的问题。(计划实施)

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。