什么是iNode
文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector),每个扇区储存512字节(相当于0.5KB),操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block),这种由多个扇区组成的"块",是文件存取的最小单位,"块"的大小,最常见的是4KB,即连续八个 sector组成一个 block。
文件数据都储存在"块"中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做iNode,中文译名为"索引节点",每一个文件都有对应的iNode,里面包含了与该文件有关的一些信息。
iNode的信息
iNode包含文件的元信息,具体有以下内容:
文件的字节数
文件拥有者的User ID
文件的Group ID
文件的读、写、执行权限
文件的时间戳,共有三个:
ctime:iNode上一次变动的时间
mtime:内容上一次变动的时间
atime:上一次打开的时间
链接数,即有多少文件名指向这个iNode
文件数据block的位置
stat命令,查看文件的iNode信息
stat update.sh
File: `update.sh'
Size: 2066 Blocks: 8 IO Block: 4096 regular file
Device: ca40h/51776dInode: 665052 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2019-05-20 10:43:42.786067647 +0900
Modify: 2018-05-07 20:36:34.088617320 +0900
Change: 2018-05-07 20:36:34.092617775 +0900
除了文件名以外的所有文件信息,都存在iNode之中
iNode的大小
iNode也会消耗硬盘空间,因此硬盘格式化的时候,操作系统自动将硬盘分成两个区域,一个是数据区,存放文件数据;另一个是iNode区(iNode Table),存放iNode包含的信息。
每个iNode节点的大小,一般是128字节或256字节,iNode节点的总数,在格式化时就给定了,一般是每1KB或每2KB就设置一个iNode,假设在一块1GB的硬盘中,每个iNode节点的大小为128字节,每1KB就设置一个iNode,那么iNode Table的大小就会达到128MB,占整块硬盘的12.8%。
使用df命令,查看硬盘分区的iNode总数和已经使用的数量:
df -i
查看每个iNode节点的大小:
sudo dumpe2fs -h /dev/hda | grep "Inode size"
由于每个文件都必须有一个iNode,因此有可能发生iNode耗尽,但硬盘还未存满的情况。这时,就无法在硬盘上创建新文件。
iNode号码
每个iNode都有一个号码,操作系统用iNode号码来识别不同的文件,对于系统来说,文件名只是iNode号码便于识别的别称。
表面上用户通过文件名打开文件,实际上系统内部这个过程分成三步:
系统找到这个文件名对应的iNode号码
通过iNode号码,获取iNode信息
根据iNode信息,找到文件数据所在的block,读取数据
使用ls -i命令,可以看到文件名对应的inode号码:
ls -i update.sh
665052 update.sh
目录文件
在Linux系统中,目录(directory)也是一种文件。打开目录,实际上就是打开目录文件。
目录文件的结构非常简单,就是一系列目录项(dirent)的列表,每个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的iNode号码。
问题解决
查看分区iNode使用情况
df -hi
如果发现某分区IUse%值为100%,这种情况说明iNode没有空间了,一般情况下是因大量小文件导致。
定位目录解决
大量小文件分布有两种可能,一是只有一个或少量目录下存在大量小文件,这种情况我们可以使用如下命令来找出这个目录:
find / -type d -size +10M
此命令作用是找出大小大于10M的目录(目录大小越大,表示目录下的文件越多)
第二种可能是,大量的小文件分布在大量的目录下,这时候上面的命令可能找不出目录,需要以下命令:
cd /
find */ ! -type l | cut -d / -f 1 | uniq -c
此命令作用是找出目录下文件总数,可能需要执行多次,直到找出具体的目录。
如上面的命令找出了/data目录下存在大量的小文件,但/data/目录还有很多目录,这时候我们还需要继续执行:
cd /data
find */ ! -type l | cut -d / -f 1 | uniq -c
直到找出具体的目录