当前位置: 首页 > 科技观察

Linux文件系统十问

时间:2023-03-13 05:34:23 科技观察

我在知乎和公众号上都提到过。2012年我在腾讯工作的时候写了一篇关于《Linux文件系统十问》的文章,总有人问我这篇文章哪里可以找到,现在网上唯一合法的链接——腾讯学院也挂了,网上搜索全是盗版。所以今天才正式发给大家。以下为本文正文。关于文件系统,相信大家都不陌生。作为攻城狮,我们几乎每天都和他们打交道,但仔细一看,其中有多少还不够深,我们无法理解。那么我们来看看下面这组Linux文件系统相关的问题:1、机械盘的随机读写速度很慢。操作系统使用了哪些技术来提高随机读写性能?2.点击a新的空文件是否占用磁盘空间?多少?3、新建一个空目录是否占用磁盘空间?多少?与新建一个文件相比,哪个占用的空间更大?4.你知道文件名记录在磁盘在哪里吗?5、最长的文件名是多长?有什么限制?6、文件名太长会影响系统性能吗?为什么会有影响?7、一个目录下最多可以创建多少个文件?8.创建一个内容大小为1k的新文件,它实际占用多少磁盘空间?9.发起命令读取文件2Byte给操作系统,操作系统实际读取多少?10、使用文件时应该怎么做可以提高磁盘IO速度吗?如果你能不假思索地回答上面80%的问题,那么请关闭本文。如果你不会,而且你也和笔者一样有窥探操作系统隐私的爱好,那么请跟着小编一起来探索一下文件系统中这些有趣的地方吧。相信了解这些对我们的工作会有很大的帮助。本文实验使用的文件系统为ext系统。一、磁盘组成与分区1、磁盘物理结构先从最基本的磁盘物理结构说起。注意本文只讨论机械盘,SSD不在本文讨论范围内。我们人类在管理任何事物之前,总是习惯划分出一定的结构,并在这个规则的基础上进行管理。军队分为军、师、旅、团、营。公司分为事业群、部门、中心、集团。然后对于管理盘,分为盘面、磁头、磁道、柱面和扇区。盘面:盘是由一堆盘面组成的,如图所示。磁头:每个磁头对应一个磁盘表面,负责读写磁盘表面的数据。.磁道:每个盘面以圆心为中心分为多个同心圆,每个圆称为一个磁道。柱面:所有盘片上相同位置的磁道组成的三维结构称为柱面。扇区:以磁道为单位来管理磁盘还是太大了,所以计算机的前辈们把每个磁道分成了多个扇区。请参见右下方的图片。我之所以爱上Linux,其中一个原因就是只要肯努力,完全可以把Linux的内在逻辑摊开,比Windows好太多了。在Linux上,可以使用fdisk命令查看当前系统使用的磁盘的物理信息。以上是我的一个虚拟机的磁盘物理信息。可以看到我的盘有255个磁头,也就是说一共有255个盘。3263柱面,也就是说每个磁盘上有3263个磁道,63sectors/track就是每个磁道上有63个扇区。命令结果还显示Sectorsize的值为512字节。然后让我们计算磁盘的大小。255个磁盘*3263个柱面*63个扇区*每个扇区512字节=26839088640字节。结果为26.8G,与磁盘总大小基本一致(至于fdisk给出的详细结果,相差4M左右,笔者也没有完全理解,有兴趣的读者可以继续研究)。不过需要注意的是,上面的磁盘等数据都是逻辑的,是物理磁盘映射转化而来的。关于这个转换关系,我还没有找到什么特别好的资料。2、分区分区是操作系统对磁盘进行管理的第一步,这也是我们任何一个计算机用户都非常熟悉的概念。例如Windows下的C、D、E、F盘。那请大家想一想,想一想:前面磁盘的详细物理结构已经有了,如果让你把整个磁盘分成C、D等分区,你会怎么划分?方案一:255个盘,C盘为0-100个盘,D盘为101-200个盘,...方案二:3263个柱面,C盘0-1000个柱面,D盘1001-20001个柱面,...为以上两种方案,你会选择哪一种呢?先说磁盘IO的过程。第一步是径向移动磁头以找到数据所在的磁道。这部分时间称为寻道时间。第二步,找到目标磁道,旋转磁盘,将目标扇区移动到磁头底部。第三步是向目标扇区读取或写入数据。至此,一次磁盘IO完成。因此,单次磁盘IO时间=寻道时间+旋转延迟+存取时间。对于轮转延迟,现在主流服务器多采用1W转的磁盘,每次轮转需要的时间为60*1000/10000=6ms,所以轮转延迟为(0-6ms)。至于访问时间,一般需要很短的时间,就是零点几毫秒。对于寻道时间,现代磁盘约为3-15ms,寻道时间主要受磁头当前位置与目标磁道位置的相对距离影响。事实上,使用哪一个主要取决于该方法的更快性能。因为同一个分区下的数据经常是一起读取的,如果采用第一种方法,那么磁头需要在3000多条磁道之间来回跳转,这样磁盘寻道时间就会成倍增加,磁盘性能也会下降加以改进。会下降。至于第二种方案,如果是C盘,只需在1-1000磁道之间移动磁头即可,大大减少了寻道时间。(其实分区并不是从0开始的,磁盘第一磁道对应的柱面会用来安装bootloader和磁盘分区表)。所以方案二的分区方式可以减少磁盘IO时间中的寻道时间部分,所以所有的操作系??统都采用方案二,方案一就没有用了。如果您在Linux下使用过fdisk进行分区,您会注意到以下信息。这充分证明操作系统采用了第二种方案。回到一开始的问题1,操作系统使用了哪些技术来降低随机读写的性能?操作系统根据磁道对应的柱面划分分区,减少磁盘IO的寻道时间,从而提高磁盘性能。读写性能。二、目录和文件1、介绍完了,磁盘的基础也说完了,接下来我们就正式进入正题,开始我们关于Linux文件系统的讨论。文件系统不就是目录和文件吗?这两个是我们熟悉的家伙,再熟悉不过了。但你确定这不是你熟悉的陌生人吗?我先新建一个空目录和空文件,查看结果如下图:我们都知道第五列显示的是占用空间,那我就提几个小问题。1)为什么目录4096占用空间?2)为什么空文件占用的空间是0?3)如果空文件确实占用0字节空间,那么文件的文件名、创建者、权限-rw-rw-r——文件夹相关信息存放在哪里?2.我不相信空文件不占空间。要解开这个谜团,就需要使用df命令。输入df–i,Linux结果中的红框显示了inode的相关信息。如果对inode这个概念不熟悉的话,可以暂时把它看成操作系统暗中管理的一个家伙,会占篇幅的。接下来,我再次触摸一个空文件和df-i。虽然之前的操作系统告诉我们一个新创建的空文件占用的空间是0。但是这个实验证明操作系统“欺骗”了我们,它消耗了一个inode。那么inode的节点大小是多少呢?使用dumpe2fs命令可以帮助我们查看这个东西的实际大小。在输出结果中我们可以找到下面一行。它告诉我们每个inode的大小是256Byte。当然这个大小每个机器都会不一样,其实是系统格式化磁盘的时候决定的。嗯,开头的第二个问题也有答案了。原来创建一个空文件会占用磁盘空间,实际占用是256Byte。哦,不对,准确的说法应该是一个inode大小,具体的值是在格式化的时候决定的。让我们谈谈创建一个空目录。如前所述,创建一个空目录将占用4KB的磁盘空间。那么仅此而已吗?我们还使用df-i来监控创建新目录前后的系统inode占用情况。原目录也会占用一个inode节点,第三个问题也得到解答。创建一个空目录将占用4KB+inode大小的磁盘空间。哦,这不一定是你系统上的4K,它实际上是一个块大小。在dumpe2fs下也可以看到同样的情况。只是我的盘被格式化成4KB大小了,呵呵!3.4KB前的神秘空目录之谜解开了,可以当攻城狮的我,又开始好奇另一件事了。就是空目录占用的4KB。这个空间是做什么用的?太神秘了。cd到我们新建的目录下查看。让我们再创建两个空文件,然后查看目录的空间使用情况。显然,没有发现任何新东西。因为空文件是不占块的,所以这里还是显示了目录占用的块,大小和之前没有变化。然后我继续使用php脚本创建100个文件名长度为32字节的空文件。这时我们发现目录占用的磁盘空间变大了,变成了3个Blocks。哈哈,这就回答了我们开头的第四个问题,文件名存放在目录占用的block中。接下来我还证明了每个目录块可以保存的文件名个数与文件名的长度有关(好像有点废话,但是自己证明自己的猜测还是有点爽)。我还新建了一个空目录,新建了100个空文件,文件名长度为32*3。这个临时目录占用的磁盘空间如下:你可能会问我为什么文件名变大了三倍。为什么块的数量没有增加三倍。其实在Linux文件系统中,文件的结构除了文件名之外,还有其他字段。如果文件名变长三倍,结构将不会变大三倍。关于这一点,可以参考Linux系统内核相关的书籍。好了,现在我们有了第6个问题的答案。长文件名当然会对系统性能产生影响,因为这可能会导致更多的磁盘IO。很多程序员喜欢把文件命名为有意义的长字符串,让人一眼就知道用途。当然,我没有说这样不好,但是如果你的文件很多,你就要考虑是不是你的文件名导致你的目录块占用太多了。占用的空间很小,磁盘也很便宜,但是在目录中查找文件时,你必须考虑操作系统的感受。名称下的所有块都应该重新完成。(当然,你的文件名长度没有异常,如果数量没有达到10万的量级,开销不会太大,但是这个开销你应该知道。)至于开题5,如何最长的文件名是多少?长的。事实上,Linux操作系统为了防止程序员无节制地使用长文件名,对文件名进行了255字节的限制。另外,大家有没有遇到过,当目录下的文件很多的时候,我们用ls命令的时候会很慢。现在大家都知道原因了。这个时候操作系统实际上是在读取当前目录下的所有块。如果有很多块,可能需要多次IO操作才能完成这个简单的ls命令。我在我电脑的某个目录下创建了一个100W的空文件,ls命令1分钟没有出结果,于是我ctrl+c删掉了。不要在你自己的项目中这样做。虽然操作系统可以缓存你的目录数据,让你下次调用的时候快很多,但是我还是建议你一个目录下的文件不要超过10000个。否则,您的程序在重新启动后第一次运行时可能会遇到性能不佳的情况。好了,回到开篇的问题7,你有答案了吗?一个目录最多可以创建多少个文件,这个其实是受你目录所在分区的inode数量限制的,你有100W个inode,你最多可以创建100W个新文件。但是,如上所述,单个目录下的文件数不能超过10000个,否则会导致系统性能出现问题。4、对于文件的block,再做一个关于文件的实验。我新建了一个空目录,并在其下新建了一个文件,里面只写了一个空白数据。保存后,du命令显示如下:8K中的4K是目录,可以计算出操作系统只包含一个带空格的文件分配了4KB。其实文件的block比较简单。与目录的块存储许多文件系统结构不同,文件的块只保存文件的数据。上面的实验表明,操作系统分配空间时,块是最小的单位。也就是说,只要你的文件数据不为空,操作系统至少会分配一个块用于存储,直到你超过4KB,操作系统再分配下一个块给你,就这样。所以对于开题8,新建一个内容大小为1k的文件,实际上会占用1个block(通常是4k)和一个inode(通常是256byte)。实际上,文件系统在向磁盘发起IO请求时,也是以块大小为单位的。即使你只向操作系统发起读取文件的2Bytes,操作系统也会一次为你读回4KB。所以磁盘IO真的很慢,只要我们访问这2Byte,确实很有可能继续访问这2Byte后面的内容。这就是程序局部性的原则,所以操作系统只是一次读取更多。有些人回来了。呵呵,这就是开头第9题的答案。就像我们去超市一样。去逛一次真的很浪费时间,比作弊的磁盘IO慢多了。我们永远不会去超市逛逛,买了一个苹果然后回来。我们一定会买更多的东西,为家人将来的需要做准备。反正买一堆东西并不比买一个苹果多花多少时间。为什么不这样做,这就是原因。说说开题10.我们如何设计你的文件来提高IO速度?也就是说,如果你知道你的新文件会占用多少空间,比如1M。然后当你新建一个文件的时候,顺便告诉操作系统,让它帮你预留文件的大小。这样,操作系统实际上会尽可能的为你分配连续的块,这样当你再次读取文件时,head会节省大量的寻道时间,IO速度也会显得快很多。3.后面写的字都是基于我自己的文件系统。情况是一个块大小是4KB,一个inode大小是256byte。包括我的虚拟机上的inode数也只有140万多。这些值其实不是固定的,格式化硬盘的时候可以设置其他值。设置的原则是看你硬盘的容量和你的使用情况。如果你的文件大于4KB,甚至是几M,几G,那么建议你的block尽量大,这样可以在inode中保存几个地址。如果你的大部分文件都在1K以下,那么使用4K块会造成一点浪费。如果你的老板对成本要求极高,你可以适当考虑把你的block设置小一些。另外,请注意您的文件系统的索引节点。操作系统在查看目录和文件占用的磁盘空间信息时隐藏了inode节点的占用情况。隐藏信息是为了让我们更容易理解操作系统。其实,作为非普通用户的开发者,我们应该有这个知情权。这个东西直接关系到你的文件系统能创建的文件数量。不然有一天你会发现线上的机器磁盘还有很多空间,但是inode用完了,这时候你就得重新格式化或者迁移服务器了。这两个操作很难想,所以可以尽量避免。思考题:大家都有过这样的经历,当一个目录下的小文件太多的时候,复制到其他地方的速度会很慢。这时候,我们往往会压缩目录,然后复制。现在你能说出为什么它更快吗?最后,我想再说一件事。这篇九年前写的文章,今天看来还是很有用的。由此可见,内劲识的生命周期是很长的。另一方面,我练过的大部分外挂技能,比如PHP、Jquery等开发知识,都快过时了。这也是我创立公众号《内功修炼养成篇》,让大家一起修炼内功的一个重要原因。正确锻炼内功,是你对抗科技升级、缓解中年焦虑的一剂良药。