前几天在红黑联盟上看了一篇博客《Linux文件系统十问—深入理解文件存储方式》,上一篇博客简单的了解了一下linux文件系统,所以想自己再深入理解一下这十个问题。
先来看看这十个问题:
1、机械磁盘随机读写时速度非常慢,操作系统是采用什么技巧来提高随机读写的性能的?
2、touch一个新的空文件占用磁盘空间吗? 占用的话占用多少?
3、新建一个空目录占用磁盘空间吗?占用多少?和新建一个文件相比,哪个占用的更大?
4、你知道文件名是记录在磁盘的什么地方吗?
5、文件名最长多长?受什么制约?
6、文件名太长了会影响系统性能吗?为什么会产生影响?
7、一个目录下最多能建立多少个文件?
8、新建一个内容大小1k的文件,实际会占用多大的磁盘空间?
9、向操作系统发起读取文件2Byte的命令,操作系统实际会读取多少呢?
10、我们使用文件时要怎么样来能提高磁盘IO速度?
一:磁盘构成及分区
1:磁盘的物理结构
先说一下磁盘的物理结构,这里机械硬盘,固态硬盘SSD这里不做讨论。对于管理磁盘,分磁盘面,磁头,磁道,柱面和扇区。
- 磁盘面:一个磁盘是由一叠组成的。
- 磁头(heads):每个对应一个磁盘面,负责该磁盘面上的数据读写。
- 磁道(track):每个圆心划分出多个同心圆圈,每个圆圈叫做一个磁道。
- 柱面(cylinders):所有盘面上的同一位置的磁道组成的立体叫做一个柱面。
- 扇区(sector):以磁道为单位管理磁盘仍然太大,所以又把每个分出了多个扇区。
如图:
在原文章中笔者用fdisk -l查看了当前系统使用磁盘的物理信息,结果可以磁头数,磁道,扇区数等等。
可以看出他的磁盘有255个heads,也就是说共有255个盘面。3263个cylinders,也就是说每个盘面上都有3263个磁道, 63sectors/track说的是每个磁道上共有63个扇区。命令结果也给出了Sector size的值是512bytes。算一下该磁盘的大小:
255盘面 3263柱面 63扇区 * 每个扇区512bytes = 26839088640byte。
结果是26.8G,和磁盘的总大小相符(至于fdisk给出的详细结果相差了约4M的大小,笔者也没有弄彻底明白,有兴趣的读者可以继续研究)。
另外查看了其它两台机器的磁盘情况,发现个有意思的事情。如下图,无论磁盘的容量大或者是小,其磁头数和每磁道扇区数都是不变的,只是磁道变多了而已。
2:分区
分区的话,我们先根据磁盘的物理结构两个方案:
方案一: 255个盘面,C盘是0-100盘面, D盘是101-200个盘面,……
方案二:3263个柱面,C盘0-1000个柱面,D盘1001-20001个柱面,……
要想选取两种方案较高效的一个,我们先来看一下磁盘IO时的过程。第一步,首先是磁头径向移动来寻找数据所在的磁道。这部分时间叫寻道时间。第二步,找到目标磁道后通过盘面旋转,将目标扇区移动到磁头的正下方。第三步,向目标扇区读取或者写入数据。到此为止,一次磁盘IO完成,故:
单次磁盘IO时间 = 寻道时间 + 旋转延迟 + 存取时间。
同一分区的数据经常会一起读取,所以再来看看两种方案,如果使用方案一的话,磁头就需要在多个磁道间不停地跳来跳去,这样磁盘的寻道时间就会翻倍,磁盘性能就会下降。对于方案二的话,磁头只需要在较少量的磁道移动即可,大大降低了寻道时间。
所以,方案二的分区方式可以降低磁盘IO时间中的寻道时间部分,所以所有的操作系统采用的都是方案二,没有用方案一的。
在Linux下使用过fdisk进行分区的话可以注意到以下信息:
这充分证明了操作系统是采用方案二的。
回到开篇提出的问题1,操作系统是采用什么技巧来降低随机读写的性能问题的呢?操作系统通过按磁道对应的柱面划分分区,来降低磁盘IO所花费的的寻道时间 ,进而提高磁盘的读写性能。
二:目录与文件
1:引出问题
将磁盘的基础简单了解,我们正式来看一下linux的文件系统。那么,对于文件系统中我们熟悉目录和文件我们又了解多少呢?先来创建一个空的目录和文件:
我们知道,ls命令第五列显示的是文件占用空间的大小,那么,先来提出几个问题:
- 为什么目录目录占用的空间是4096?
- 为什么空文件占用的空间是0?
- 如果空文件占用的空间是0,那么该文件的文件名,权限等相关属性存在哪里?
2:空文件不占空间?
这里用一下df -i命令。
其实我们可以根据以上命令发现在创建了一个新文件时,消耗掉了一个inode,inode的概念前面博文有讲。
inode的大小可以用dumpe2fs查看:
可以看到一个inode有256bytes大小。
所以,我们可以回答开篇提出的第二个问题,当touch一个新文件时其实是占用磁盘空间的,实际占用是一个inode的大小,inode的大小在文件系统格式化的时候就已经确定。
再来说新建目录,同样,使用df -i命令来查看:
可以看出,新建一个空目录也会占用一个inode。所以,现在开篇的第三个问题也有答案了,新建一个空目录时,占用的空间是1个block+1个inode。
3:空目录的4KB
特地查看了一些目录,发现不管目录里内容的多少,目录所占空间大多都是4K。那么这4K是干什么的呢?
先进入建立的空目录查看:
接着建立两个新的空文件:
空文件不占block,所以,4K还是没什么变化。这时创建更多的文件名长的空文件:
这时,4K就变成了12K。占用了3个block。所以开篇的第四个问题就有了答案,文件名是存在目录所占用的block中的。
所以,第六个问题我们现在也可以回答了,文件名太长对系统性能当然会有影响,因为这可能会导致更多的磁盘IO。如果文件名特别特别长,文件数量相当大的时候就要考虑文件名是否导致目录所占的block太多。占空间大小倒是小事,磁盘便宜,但是你得考虑下在目录下查找文件时操作系统的感受,操作系统可需要用你你提供的文件名进行字符串比较,而且运气不好的话需要将其名下所有block都搞一遍才行啊。(当然了,你的文件名长度不变态,而且数量没有达到十万数量级的话实际上这个开销也不会太大,但是这个开销你还是知道的为好)
来说开篇问题五,文件名最长多长呢?linux系统为了避免程序员不节制地使用长文件名,强加了个限制,不能超过255byte。
开篇问题七,一个目录下能创建多少个文件?其实这个最多是受限与你目录所在分区的inode数量。有一百万个inode,你最多就可以新建一百万个文件。但是,单个目录下文件数量最好不要过万,否则会带来系统性能的问题。
4:文件的block
来做个关于文件的实验,创建一个空目录,然后在其下建立一个空文件,在这个文件里写入一个数字再保存。
8K中有4K是目录的,也就是说系统为一个只有一个数字的文件分配了4K。其实文件的block比较简单的了,不像目录的block里会存很多文件系统的结构体,文件的block里只会保存文件的数据。上面这个实验表明,操作系统分配空间时是以block为最小单位。也就是说只要你的文件数据不为空,操作系统就至少会给你分配一个block来存储,直到你超过了4KB,操作系统再给你分配下一个block。
开篇问题八:新建一个1K大小的文件实际会占用一个block大小的空间。
开篇问题九:文件系统在向磁盘发起IO请求时也是一block size为单位的,向操作系统发起读取文件的2byte,操作系统会一次性读给你1个block大小。因此磁盘的IO很慢。
开篇问题十:使用文件时要怎么样来能提高磁盘IO速度?原理就是尽量将一个文件的block连续一些。这个前面有讲到。如果知道要新建的文件大概有多大,就在创建时给操作系统说一下,将文件的大小预留下来。这样就尽可能的为一个文件分配到连续的block,再读取文件时磁头就会省去很多寻道时间,IO速度就会明显快一些。
感谢阅读,欢迎指正。