文件系统之inode应用场景解析

Posted by suleo on April 23, 2021

文件系统之inode应用场景解析

一、linux文件系统基本概念

1. 块/扇区

  • 文件储存在硬盘上,硬盘的最小存储单位叫做 “扇区“(Sector),每个扇区储存512字节

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

    inode1

    番外:有次跟同事排查bug,解决完之后我突然想起来这个块的概念,我说咱们这个系统上最小的文件都得至少占4k,他说怎么会呢,一大堆小于4k的,结果就是用du查看之后,我获得了免费晚餐

2. Inode

  • Inode概念

    文件数据都储存在”块”中,所以还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等。这种储存文件元信息的区域就叫做inode

    当我们创建一个文件的时候,inode编号将作为该文件的唯一id,即,一个文件在同一时刻仅拥有一个inode编号。当我们向一个文件写入内容的时候,数据被存放到了data block当中。而该文件的文件名,被存放到了该文件所在的目录文件当中。

  • inode元信息

    文件的字节数
    文件拥有者的User ID
      
    文件的Group ID
    文件的读、写、执行权限
    文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。
      
    链接数,即有多少文件名指向这个inode
    文件数据block的位置
    
  • inode大小

    • inode也会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是inode区(inode table),存放inode所包含的信息

    • 每个inode节点的大小,一般是128字节或256字节。inode节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个inode。假定在一块1GB的硬盘中,每个inode节点的大小为128字节,每1KB就设置一个inode,那么inode table的大小就会达到128MB,占整块硬盘的12.8%

    • 查看每个硬盘分区的inode总数和已经使用的数量,可以使用df命令 df -i

      inode3

    • 查看inode节点大小

      首先查看指定分区文件系统类型(centos7之后文件系统默认使用XFS,之前为EXT4)blkid /dev/sda1

      截屏2021-04-23 16.19.09

      查看文件系统信息

      isize为inode大小,在xfs文件系统中inode大小由之前的EXT4文件系统中默认的256字节扩展至512字节

      截屏2021-04-23 16.21.29

      # 输出信息解读
      isize = 512:一个inode占用空间的大小。
      bsize = 4096:一个块大小。可以可知当前文件系统中一个块可以放置8个inode。
      agcount = 4:ag是xfs文件系统的最初的级组织结构,全称是allcation组。一个xfs文件系统是由几个个ag组成的。可以在格式化xfs的时候指定ag个数,通常是4个ag 。
      agsize = 1310656:每个ag所包含的block块数。
      sectsz = 512:磁盘插入大小。
      finobt = 1:自Linux 3.16起,XFS增加了B +树用作索引重定向使用的inode。这是这个开关是否打开的选项。1表示打开。
      rmapbt = 0:rmapbt功能关闭。
      blocks = 5242624:分区包含的所有block总数。
      
  • 查看文件inode号 ls -i filename

    截屏2021-04-23 16.34.10

  • 查看文件inode信息 :stat filname

    inode1

3. 目录文件

  • 概念

    在学习文件系统之前,我以为目录里面存放着文件。但是真实的情况是目录里面并不存放文件以及文件数据。Unix/Linux系统中,目录也是一种文件,打开目录,实际上就是打开目录文件

    目录文件的结构非常简单,就是一系列目录项的列表。每个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的inode号码。

    当我们不小心用vim打开了一个目录的时候,我们总是看到一些目录相关的一些信息

  • 查看目录inode信息 ls -i /root

    截屏2021-04-23 16.46.39

  • 查看目录更详细的信息 ls -l /root

    截屏2021-04-23 17.00.18

    目录文件的读写执行权限,都是针对目录文件本身

    由于目录文件内只有文件名和inode号码,所以它对应的权限如下

    • 读(r):表示具有读取目录结构列表的权限,表示你可以查询该目录下的文件名数据,可以利用ls命令将该目录的内容列表显示出来
    • 写(w):表示你具有更改目录结构列表的权限,包括以下权限:
      • 新建文件和目录
      • 删除已存在的文件和目录
      • 重命名已存在的文件和目录
      • 转移该目录下的文件和目录
    • 执行(x):表示用户可以进入该目录作为工作目录

二、应用场景解析

1. 文件存取过程

1. 根据`Filename`,通过Dircetory的映射关系找到对应的`Inode number`,例如:`Inode:1314521`。
2. 根据`Inode number`读取到文件的`Inode table`
3. 再根据`Inode table`中的`Pointer`读取到对应的`Blocks`

感觉有点dns解析那意思

文件名只是inode的一个alias,Unix/Linux系统内部使用inode来识别文件。使用ls -i test.js可以查看一个文件的Inode number

若通过filename删除失败,可以直接删除inode节点

2. 硬链接和软链接

硬链接

一般情况下,文件名和inode号码是”一一对应”关系,每个inode号码对应一个文件名。但是,Unix/Linux系统允许,多个文件名指向同一个inode号码

使用ln 源文件 目标文件可以创建硬链接,此时链接数+1

截屏2021-04-23 17.14.13

源文件与目标文件的inode号码相同,都指向同一个inode,可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所有文件名;但是,删除一个文件名,不影响另一个文件名的访问,只是链接数会-1, 当这个值减到0,表明没有文件名指向这个inode,系统就会回收这个inode号码,以及其所对应block区域

扩展: 创建目录时,默认会生成两个目录项:”.”和”..”, 前者的inode号码就是当前目录的inode号码,等同于当前目录的”硬链接”;后者的inode号码就是当前目录的父目录的inode号码,等同于父目录的”硬链接”。所以,任何一个目录的”硬链接”总数,总是等于2加上它的子目录总数(含隐藏目录)

软链接

创建软链接 ln -s test.txt test_sl.txt, 接着查看当前目录文件inode信息 ll -i

截屏2021-04-23 17.25.31

软链接就是一个普通文件,只是数据块内容有点特殊,文件用户数据块中存放的内容是另一文件的路径名的指向,通过这个方式可以快速定位到软连接所指向的源文件实体

文件test_sl.txt和文件test.txt的inode号码虽然不一样,但当读取文件test_sl.txt时,系统会自动将访问者导向文件test.txt。因此,无论打开哪一个文件,最终读取的都是文件test.txt。这时,文件test_sl.txt就称为文件test.txt的”软链接”(soft link)或者”符号链接(symbolic link)

如果删除了文件test.txt,打开文件test_sl.txt就会报错:”No such file or directory”。这是软链接与硬链接最大的不同:文件test_sl.txt指向文件test.txt的文件名,而不是文件test.txt的inode号码,所以文件test.txt的inode”链接数”不会因此发生变化

扩展: 软链接作用

  • 便于文件的管理,比如把一个复杂路径下的文件链接到一个简单路径下方便用户访问。
  • 节省空间解决空间不足问题,某个文件文件系统空间已经用完了,但是现在必须在该文件系统下创建一个新的目录并存储大量的文件,那么可以把另一个剩余空间较多的文件系统中的目录链接到该文件系统中。
  • 删除软链接并不影响被指向的文件,但若被指向的原文件被删除,则相关软连接就变成了死链接。
硬链接和软链接的区别
  • 硬链接可认为是一个文件拥有两个文件名

  • 而软链接则是系统新建一个链接文件,此文件指向其所要指的文件

  • 硬链接的局限性
    • 软链接可以跨文件系统;硬链接不可以
    • 软链接可以对一个不存在的文件进行链接;硬链接不可以
    • 软链接可以对目录进行连接,硬链接不可以
    • 软链接又叫符号链接,相当于windows中的快捷方式
  • ⚠️注意:对于目录软链接

    rm ln_dir 是删除软链接
    rm ln_dir/ 是删除目录ln_dir中的文件,当然源目录中的文件也会删除
    

3. mv和cp命令底层依赖

inode是识别一个文件的核心,移动文件或重命名文件,只是改变文件名,不影响inode号。

一个文件打开或执行后,系统就以inode号码来识别,所以项目可以在不关闭软件的的情况下进行更新,不需要重启。因为系统通过inode号码,识别运行中的文件,不通过文件名。更新的时候,新版文件以同样的文件名,生成一个新的inode,不会影响到运行中的文件。等到下一次运行这个软件的时候,文件名就自动指向新版文件,旧版文件的inode则被回收。

strace跟踪系统调用

大部分Unix系统支持strace调用kernel和ptrace接口实现系统调用。strace常用来跟踪进程执行时的系统调用和所接收的信号。 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。

  1. 查看rm命令的系统调用:strace rm -rf test_hl.txt

    截屏2021-04-23 17.50.54

    输出的每一行都显示了一个系统调用、参数及返回值。

    unlinkat : 该调用是解除文件的链接,即删除文件名。使源目录不再含有此文件名。当该文件的链接数为1且没有进程打开此文件时,才会真正删除文件内容。所以,用该方法直接删除打开的文件是安全的。

  2. 查看mv命令的系统调用: mv test.txt test.txt.bak

    截屏2021-04-23 17.58.01

    综上,mv命令首先检查初始文件和目标文件是否存在访问权限,然后是通过rename指令实现系统调用。目标文件存在时,mv的行为类似于rename的行为,该行为会导致inode节点发生变化,所以mv更新文件相当于删除文件后在新建一个同名文件。

  3. 查看cp命令的系统调用:cp test.txt.bak test.txt

    截屏2021-04-23 18.01.42

    执行cp命令后文件inode号没有改变,cp 使用了 open 及O_TRUNC 参数打开了目标文件,因此cp更新操作是将目标文件内容清空,然后把新的内容写入目标文件。

mv命令与cp命令更新文件对比
对比 mv cp
更新方式 删除->替换 清空->写入
属组和属主 属组和属主不变 属组或属主改变
inode节点 改变 不改变

4. logrotate之日志清理

简单来说,logrotate有两种模式,create和copytruncate

  • 创建模式:

    • logrotate重命名正在写入文件的文件名,由于读写文件使用文件inode,所以重命名不影响日志继续写入
    • 原程序使用inode继续往旧日志文件写日志
    • 程序重新发布,触发程序获取信息

    • 这种方式需要依赖程序有重载功能,一般kill -HUP pid能触发程序relaod,nginx还可以使用kill -USR1 pid单独触发日志relaod
  • copytruncate模式:

    • 对老日志文件进行复制,生成日志的备份

    • 程序清空日志文件,例如echo > logfile

    • 程序继续清空后,通过程序使用O_APPEND方式打开日志文件,日志便能重第一行开始重新写入

    • 这种方式会存在日志丢失的风险。