Linux文件系统:新建一个空文件占用多少磁盘空间?只有1个字节的文件实际占用多少磁盘空间?

目录

新建一个空文件占用多少磁盘空间?

实践出真知

细说Inode

文件名存到哪里了

结论

只有1个字节的文件实际占用多少磁盘空间

查看1个字节的文件

继续讨论这个4K

文件内容大了怎么办?

结论

推荐阅读


 

新建一个空文件占用多少磁盘空间?

https://mp.weixin.qq.com/s?__biz=MjM5Njg5NDgwNA==&mid=2247483902&idx=1&sn=01ceb6988adcbcac6da6ea6dafe57039&chksm=a6e300c5919489d32e5e9f5ba065710a1a22f74523a06c1661b4a2ee0d631c3297f1abf766a1&mpshare=1&scene=1&srcid=1209jvE7xDwmR1Vn0ZMtU3TU&sharer_sharetime=1607488225091&sharer_shareid=c99e16b7425e9481e4f952398ef9efc3&key=985be40c305f941f19b8987fa56e44d39bcb8ba2c948d76b7ecf3ca2cffab8fc66ed6410ac3733c7d6e0b5f85db8d033ae33c3c181225497a3ce5f03a67f982a3a4641f9d943a32db616f90e6f658c0d89b38dda0dc7a6caa842ad091632313df6b86c3219cb7c8db57f740b223cda4d7425aa4b84a94302a241b1afaa62b17e&ascene=1&uin=NjczMTY5MzU3&devicetype=Windows+10+x64&version=6300002f&lang=zh_CN&exportkey=A7Wwj94I6x8YKLX%2FCCU4dg0%3D&pass_ticket=Oueq6QUBYKJ1pjroAuWiFf1ompsaRTw8kONhD07%2Fl6lW4%2FvsDeF1KP4hN4hydCpU&wx_header=0


今天我们来思考一个简单的问题。在Linux下你用touch命令新建一个空文件:

touch empty_file.txt

操作完成后,是否要消耗掉我们的一些磁盘空间?需要的话,大概能消耗多少?嗯,是的,这个问题简单的超乎你的想象,但是不知道你否能给你自己一个满意的答案。

我前面的几篇文章都是介绍的磁盘物理层面的构成,但这对于理解文件相关的问题帮助可能还不够。从今天开始让我们从物理层往上走,到Linux文件系统原理里去寻找答案。

 

实践出真知


我觉得可能先丢开内核原理,直接动手操作来实验更有意思一些。你一定知道ls这个命令你可以查看文件大小,那么让我们就用它来看一下。

# touch abcdefghigklmn.txt  
# ls -l  
total 0  
-rw-r--r-- 1 root root 0 Aug 17 17:49 empty.file

额,ls命令告诉我这个空文件占用的是0。文件的大小确实是0,因为我们还没有为该文件写入任何内容。但是我们现在要思考的是,一个空文件是否占用磁盘空间。所以直觉告诉我们这绝对不可能,磁盘上多出来一个文件,怎么可能一点空间开销都没有!

为了解开这个谜底,还需要借助df命令。输入df –i

# df -i
Filesystem            Inodes   IUsed   IFree IUse% Mounted on
......
/dev/sdb1            2147361984 12785019 2134576965    1% /search

这个输出帮我们展示了我们文件系统中inode的使用情况。注意IUsed是12785019。我们继续新建一个空文件:

# touch empty_file2.txt
df -i
Filesystem            Inodes   IUsed   IFree IUse% Mounted on
......
/dev/sdb1            2147361984 12785020 2134576964    1% /search

这下注意IUsed变成了12785020

哈哈,我们的一个结论就出来了。新建一个空文件会占用一个Inode。

 

细说Inode


那么inode里都存了哪些和文件相关的信息呢?我们再稍微看一下内核的源代码。大家可以下载一份linux的源代码。以ext2文件系统为例,在我下载的linux-2.6里的文件fs/ext2/ext2.h中,可以找到内核对于inode结构体的定义。该结构体较为复杂,主要存储除了文件内容以外的一些其他数据,我们选一些比较关键的截取出来:

struct ext2_inode {
        __le16  i_mode;         # 文件权限
        __le16  i_uid;          # 文件所有者ID
        __le32  i_size;         # 文件字节数大小
        __le32  i_atime;        # 文件上次被访问的时间
        __le32  i_ctime;        # 文件创建时间
        __le32  i_mtime;        # 文件被修改的时间
        __le32  i_dtime;        # 文件被删除的时间
        __le16  i_gid;          # 文件所属组ID
        __le16  i_links_count;  # 此文件的inode被连接的次数
        __le32  i_blocks;       # 文件的block数量
        ......
        __le32  i_block[EXT2_N_BLOCKS]; # 指向存储文件数据的块的数组
        ......

可以看到和文件相关的所属用户、访问时间等都是存在inode中的。另外在include/linux/fs.h中,还有个VFS层面的inode的定义,这里咱就不发散了。使用stat命令就可以直接看到文件inode中数据。

# stat test
  File: `test'
  Size: 0               Blocks: 0          IO Block: 1024   regular empty file
Device: 801h/2049d      Inode: 26          Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2020-03-01 12:14:31.000000000 +0800
Modify: 2020-03-01 12:14:31.000000000 +0800
Change: 2020-03-01 12:14:31.000000000 +0800

每个inode到底是多大呢?dumpe2fs可以告诉你(XFS的话使用xfs_info)。

# dumpe2fs -h /dev/mapper/vgroot-lvroot
dumpe2fs 1.41.12 (17-May-2010)
......
Inode size:               256

Inode size表示每个Inode的大小。我的这台机器上,每个inode都是256字节。两个inode的大小正好对齐到磁盘扇区的512字节。

 

文件名存到哪里了


Inode结构体都看完了,搞了半天不知道有没有发现一个问题,inode里并没有存储文件名!!那么,文件名到底跑哪儿去了?

fs/ext2/ext2.h中,我找到了如下文件夹相关的结构体

struct ext2_dir_entry {
         __le32  inode;                  /* Inode number */
         __le16  rec_len;                /* Directory entry length */
         __le16  name_len;               /* Name length */
         char    name[];                 /* File name, up to EXT2_NAME_LEN */
};

这个结构体就是我们司空见惯的文件夹所使用的数据结构。没错,文件名是存在其所属的文件夹中的,就是其中的char name[]字段。和文件名一起,文件夹里还记录了该文件的inode号等信息。

 

结论


  • 1. 新建一个空文件需要消耗掉一个inode,用来保存用户、创建时间等元数据。

  • 2. 新建一个空文件还需要消耗掉其所在目录的block中一定的空间,这些空间用来保存文件名,inode号等信息。

所以,看起来新建一个空文件而已,只要你想挖,真的能挖出很多知识的。最后分享一个我们团队里同学遇到的一个故障。我们的一台离线任务机直接歇菜了,重启后排查原因是inode被消耗光了。再追查发现一个进程创建了太多的空日志文件。虽然文件都是空文件,但是inode却被浪费光了。后来让负责的同学修改了创建日志文件的逻辑,删掉了多出来的空文件,该机器恢复正常。

 

只有1个字节的文件实际占用多少磁盘空间

https://mp.weixin.qq.com/s?__biz=MzUxMjEyNDgyNw==&mid=2247490208&idx=1&sn=a957d25a3710b9c6b3655afb517a2b10&chksm=f9686854ce1fe142a6fd5de15f2268ebf5d879738131513104edfe14803d0df08006729fba6b&mpshare=1&scene=1&srcid=1209ghHUGvrL396T5BQgKuSt&sharer_sharetime=1607488261607&sharer_shareid=c99e16b7425e9481e4f952398ef9efc3&key=985be40c305f941ff2079b8ab6ed871630c6290755d4e2221f44af72bbb06b2a26b353aefabb90dc55ef705a64a0c986d5128364fd6a1a4b86cda82b59f46f900f11fbf4571f264e97f9ab54b2f2ee4528f2cac1d1470a25817f38563582c69fe0970dc88950c9ebc74f989de1036f23f323696183efd184a7cdb8f43fe96935&ascene=1&uin=NjczMTY5MzU3&devicetype=Windows+10+x64&version=6300002f&lang=zh_CN&exportkey=A0VDqFN81BnBtipDr0zFLho%3D&pass_ticket=Oueq6QUBYKJ1pjroAuWiFf1ompsaRTw8kONhD07%2Fl6lW4%2FvsDeF1KP4hN4hydCpU&wx_header=0


在前文《新建一个空文件占用多少磁盘空间?》中我们了解到了一个空文件的磁盘开销。 今天我们再思考另外一个问题,假如我们给文件里只写入1个字节,那么这个文件实际的磁盘占用多大,难道真的是1个字节吗?

 

查看1个字节的文件


和前文一样,先不谈原理,直接动手操作。

# mkdir tempDir
# cd tempDir
# du -h
0    .
# touch test
# du -h
0    .

在一个目录中创建了一个空的文件以后,通过du命令看到的该文件夹的占用空间并没有发生变化。这符合我们之前的认识,因为空文件只占用inode。好,那让我们修改文件,添加一个字母

echo "a" > test
# du -h
4.0K    .

保存后再次查看该目录的空间占用。我们发现由原来的0增加到了4K。 所以说,文件里的内容不论多小,哪怕是一个字节,其实操作系统也会给你分配4K的。哦,当然了还得再算前文中说到的inode和文件夹数据结构中存储的文件名等所用的空间。 所以,不要在你的系统里维护一大堆的碎文件。文件再小,占用磁盘其实一点都不少!

注意我的实验环境是在ext文件系统下进行的。如果是xfs可能表现会有些许出入。

 

继续讨论这个4K


再把linux源代码文件fs/ext2/ext2.h里关于inode的定义翻出来,我们找到结构体中定义的指向数据节点用的block数组:

struct ext2_inode {
    ......
    __le32  i_block[EXT2_N_BLOCKS]; # 指向存储文件数据的块的数组
    ......

当文件没有数据需要存储的时候,这个数组都是空值。而当我们写入了1个字节以后,文件系统就需要申请block去存储了,申请完后,指针放在这个数组里。哪怕文件内容只有一个字节,仍然会分配一个整的Block,因为这是文件系统的最小工作单位。那么这个block大小是多大呢,ext下可以通过dumpe2fs查看。

#dumpe2fs -h /dev/mapper/vgroot-lvroot
......
Block size:               4096

在我的机器上,一个Block是4KB。

 

文件内容大了怎么办?


不知道你留意没,inode中定义的block数组大小呢,只有EXT2_N_BLOCKS个。我们再查看一下这个常量的定义,发现它是15,相关内核中定义如下:

#define EXT2_NDIR_BLOCKS        12
#define EXT2_IND_BLOCK         EXT2_NDIR_BLOCKS
#define EXT2_DIND_BLOCK        (EXT2_IND_BLOCK + 1)
#define EXT2_TIND_BLOCK        (EXT2_DIND_BLOCK + 1)
#define EXT2_N_BLOCKS              (EXT2_TIND_BLOCK + 1)

就按4K的block size来看,15个block只够存的下15*4=60K的文件。 这个文件大小相信你一定不满意,你存一个avi大片都得上G了。

那Linux是怎么实现大文件存储的呢?

嗯,其实上面宏的定义过程已经告诉你了,就是只有12个数组直接存block指针,其余的用来做间接索引(EXT2_IND_BLOCK),二级间接索引(EXT2_DIND_BLOCK)和三级索引(EXT2_TIND_BLOCK)。

图1 inode中的直接与间接索引

这样,一个文件可以使用的空间就指数倍的扩展了。 文件小的时候,都用直接索引,磁盘IO少,性能好。文件大的时候,访问一个block可能得先进行三次的IO,性能略慢,不过有OS层面的页缓存、目录项缓存的加持,也还好。

 

结论


文件系统是按照inode+block来组织的,所以不管你的文件多小,哪怕只有一个字节,在数据上都会消耗掉整整一个块(当然还得算上inode等开销)。这个块大小可以通过dumpe2fs等命令来查看。如果想改变这个块大小怎么办?对不起,只能重新格式化。

再扯的远一点,所有的文件系统理念都是按照块来分配的,包括分布式文件系统,例如HDFS。由于HDFS应用场景是各种GB、TB甚至是PB级别的数据处理。所以为了降低block的管理成本,它的block size设置的非常大。在比较新的版本里,一个block直接就是128M,你没看错,单位是M。 所以如果你没有block的概念,天天在HDFS上都保存一堆KB级别的小文件,就等着去财务处领钱吧!

 

推荐阅读


Linux虚拟文件系统:数据结构与文件系统注册、文件打开读写

Linux文件系统概述:硬盘驱动>通用块设备层>文件系统>虚拟文件系统(VFS)

Linux内核:一文读懂文件系统、缓冲区高速缓存和块设备、超级块

Linux虚拟文件系统概述

Linux文件系统直接IO原理与实现:缓存I/O、直接I/O

Linux文件系统概述:硬盘驱动>通用块设备层>文件系统>虚拟文件系统(VFS)

Linux内核:一文读懂文件系统、缓冲区高速缓存和块设备、超级块

Linux虚拟文件系统概述

进程、地址空间、文件、I/O、保护、虚拟内存

ARM SMMU原理与IOMMU技术(“VT-d” DMA、I/O虚拟化、内存虚拟化)

什么是I/O地址,I/O端口和I/O端口地址?

Linux虚拟内存管理 | 虚拟地址与物理地址映射、段错误SIGSEGV

Linux的文件系统及文件缓存知识点整理

Linux文件系统:编写一个内核文件系统

Linux文件系统直接IO原理与实现:缓存I/O、直接I/O

Linux文件系统概述:硬盘驱动>通用块设备层>文件系统>虚拟文件系统(VFS)

Linux内核:一文读懂文件系统、缓冲区高速缓存和块设备、超级块

Linux虚拟文件系统概述

进程、地址空间、文件、I/O、保护、虚拟内存

ARM SMMU原理与IOMMU技术(“VT-d” DMA、I/O虚拟化、内存虚拟化)

什么是I/O地址,I/O端口和I/O端口地址?

Linux虚拟内存管理 | 虚拟地址与物理地址映射、段错误SIGSEGV

持久内存开发套件(Persistent Memory Development Kit-PMDK) - pmem.io: PMDK

PMDK介绍

/proc 文件系统并使用/proc 进行输入

Linux虚拟文件系统概述

Linux文件系统概述:硬盘驱动>通用块设备层>文件系统>虚拟文件系统(VFS)

Linux内核:一文读懂文件系统、缓冲区高速缓存和块设备、超级块

Linux文件系统:编写一个内核文件系统

Linux系统C语言遍历系统文件系统,并查询其磁盘使用率(有效磁盘)

Linux虚拟文件系统VFS的相关数据结构和操作

Linux文件系统:Linux 内核文件描述符表的演变

Linux的文件系统及文件缓存知识点整理

Linux文件系统之:通用块处理层

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页