预计阅读本页时间:-
4.4 文件系统管理和优化
要使文件系统工作是一件事,使真实世界中的文件系统有效、鲁棒地工作是另一回事。本节中,我们将考察有关管理磁盘的一些问题。
4.4.1 磁盘空间管理
文件通常存放在磁盘上,所以对磁盘空间的管理是系统设计者要考虑的一个主要问题。存储n个字节的文件可以有两种策略:分配n个字节的连续磁盘空间,或者把文件分成很多个连续(或并不一定连续)的块。在存储管理系统中,分段处理和分页处理之间也要进行同样的权衡。
正如我们已经见到的,按连续字节序列存储文件有一个明显问题,当文件扩大时,有可能需要在磁盘上移动文件。内存中分段也有同样的问题。不同的是,相对于把文件从磁盘的一个位置移动到另一个位置,内存中段的移动操作要快得多。因此,几乎所有的文件系统都把文件分割成固定大小的块来存储,各块之间不一定相邻。
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
1.块大小
一旦决定把文件按固定大小的块来存储,就会出现一个问题:块的大小应该是多少?按照磁盘组织方式,扇区、磁道和柱面显然都可以作为分配单位(虽然它们都与设备相关,这是一种负面因素)。在分页系统中,页面大小也是主要讨论的问题之一。
拥有大的块尺寸意味着每个文件,甚至一个1字节的文件,都要占用一整个柱面,也就是说小的文件浪费了大量的磁盘空间。另一方面,小的块尺寸意味着大多数文件会跨越多个块,因此需要多次寻道与旋转延迟才能读出它们,从而降低了性能。因此,如果分配的单元太大,则浪费了空间;如果太小,则浪费时间。
做出一个好的决策需要知道有关文件大小分配的信息。Tanenbaum等人(2006)给出了1984年及2005年在一所大型研究型大学(VU)的计算机系以及一个政治网站(www.electoral-vote.com)的商业网络服务器上研究的文件大小分配数据。结果显示在图4-20,其中,对于每个2的幂文件大小,在3个数据集里每一数据集中的所有小于等于这个值的文件所占的百分比被列了出来。例如,在2005年,59.13%的VU的文件是4KB或更小,且90.84%的文件是64KB或更小,其文件大小的中间值是2475字节。一些人可能会因为这么小的尺寸而感到吃惊。

我们能从这些数据中得出什么结论呢?如果块大小是1KB,则只有30%~50%的文件能够放在一个块内,但如果块大小是4KB,这一比例将上升到60%~70%。那篇论文中的其他数据显示,如果块大小是4KB,则93%的磁盘块会被10%最大的文件使用。这意味着在每个小文件末尾浪费一些空间几乎不会有任何关系,因为磁盘被少量的大文件(视频)给占用了,并且小文件所占空间的总量根本就无关紧要,甚至将那90%最小的文件所占的空间翻一倍也不会引人注目。
另一方面,分配单位很小意味着每个文件由很多块组成,每读一块都有寻道和旋转延迟时间,所以,读取由很多小块组成的文件会非常慢。
举例说明,假设磁盘每道有1MB,其旋转时间为8.33ms,平均寻道时间为5ms。以毫秒(ms)为单位,读取一个k个字节的块所需要的时间是寻道时间、旋转延迟和传送时间之和:
5+4.165+(k/1 000 000)×8.33
图4-21的虚线表示一个磁盘的数据率与块大小之间的函数关系。要计算空间利用率,则要对文件的平均大小做出假设。为简单起见,假设所有文件都是4KB。尽管这个数据稍微大于在VU测量得到的数据,但是学生们大概应该有比公司数据中心更小的文件,所以这样整体上也许更好些。图4-21中的实线表示作为盘块大小函数的空间利用率。

可以按下面的方式理解这两条曲线。对一个块的访问时间完全由寻道时间和旋转延迟所决定,所以若要花费9ms的代价访问一个盘块,那么取的数据越多越好。因此,数据率随着磁盘块的增大而增大(直到传输花费很长的时间以至于传输时间成为主导因素)。
现在考虑空间利用率。对于4KB文件和1KB、2KB或4KB的磁盘块,分别使用4、2、1块的文件,没有浪费。对于8KB块以及4KB文件,空间利用率降至50%,而16KB块则降至25%。实际上,很少有文件的大小是磁盘块整数倍的,所以一个文件的最后一个磁盘块中总是有一些空间浪费。
然而,这些曲线显示出性能与空间利用率天生就是矛盾的。小的块会导致低的性能但是高的空间利用率。对于这些数据,不存在合理的折中方案。在两条曲线的相交处的大小大约是64KB,但是数据(传输)速率只有6.6MB/s并且空间利用率只有大约7%,两者都不是很好。从历史观点上来说,文件系统将大小设在1~4KB之间,但现在随着磁盘超过了1TB,还是将块的大小提升到64KB并且接受浪费的磁盘空间,这样也许更好。磁盘空间几乎不再会短缺了。
在考察Windows NT的文件使用情况是否与UNIX的文件使用情况存在微小差别的实验中,Vogels在康奈尔大学对文件进行了测量(Vogels,1999)。他观察到NT的文件使用情况比UNIX的文件使用情况复杂得多。他写道:
当我们在notepad文本编辑器中输入一些字符后,将内容保存到一个文件中将触发26个系统调用,包括3个失败的open企图、1个文件重写和4个打开和关闭序列。
尽管如此,他观察到了文件大小的中间值(以使用情况作为权重):只读的为1KB,只写的为2.3KB,读写的文件为4.2KB。考虑到数据集测量技术以及年份上的差异,这些结果与VU的结果是相当吻合的。
2.记录空闲块
一旦选定了块大小,下一个问题就是怎样跟踪空闲块。有两种方法被广泛采用,如图4-22所示。第一种方法是采用磁盘块链表,每个块中包含尽可能多的空闲磁盘块号。对于1KB大小的块和32位的磁盘块号,空闲表中每个块包含有255个空闲块的块号(需要有一个位置存放指向下一个块的指针)。考虑500GB的磁盘,拥有488×106 个块。为了在255块中存放全部这些地址,需要190万个块。通常情况下,采用空闲块存放空闲表,这样存储器基本上是空的。

另一种空闲磁盘空间管理的方法是采用位图。n个块的磁盘需要n位位图。在位图中,空闲块用1表示,已分配块用0表示(或者反之)。对于500GB磁盘的例子,需要488×106 位表示,即需要60 000个1KB块存储。很明显,位图方法所需空间较少,因为每块只用一个二进制位标识,相反在链表方法中,每一块要用到32位。只有在磁盘快满时(即几乎没有空闲块时)链表方案需要的块才比位图少。
如果空闲块倾向于成为一个长的连续分块的话,则空闲列表系统可以改成记录分块而不是单个的块。一个8、16、32位的计数可以与每一个块相关联,来记录连续空闲块的数目。在最好的情况下,一个基本上空的磁盘可以用两个数表达:第一个空闲块的地址,以及空闲块的计数。另一方面,如果磁盘产生了很严重的碎片,记录分块会比记录单独的块效率要低,因为不仅要存储地址,而且还要存储计数。
这个情形说明了操作系统设计者经常遇到的一个问题。有许多数据结构与算法可以用来解决一个问题,但选择其中最好的则需要数据,而这些数据是设计者无法预先拥有的,只有在系统被部署完毕并被大量使用后才会获得。更有甚者,有些数据可能就是无法获取。例如,1984年与1995年我们在VU测量的文件大小、网站的数据以及在康奈尔大学的数据,是仅有的4个数据样本。尽管有总比什么都没有好,我们仍旧不清楚是否这些数据也可以代表家用计算机、公司计算机、政府计算机及其他。经过一些努力我们也许可以获取一些其他种类计算机的样本,但即使那样,(就凭这些数据来)推断那种测量适用于所有计算机也是愚蠢的。
现在回到空闲表方法,只需要在内存中保存一个指针块。当文件创建时,所需要的块从指针块中取出。现有的指针块用完时,从磁盘中读入一个新的指针块。类似地,当删除文件时,其磁盘块被释放,并添加到内存的指针块中。当这个块填满时,就把它写入磁盘。
在某些特定情形下,这个方法产生了不必要的磁盘I/O。考虑图4-23a中的情形,内存中的指针块只有两个表项了。如果释放了一个有三个磁盘块的文件,该指针块就溢出了,必须将其写入磁盘,这就产生了图4-23b的情形。如果现在写入含有三个块的文件,满的指针块不得不再次读入,这将回到图4-23a的情形。如果有三个块的文件只是作为临时文件被写入,当它被释放时,就需要另一个磁盘写操作,以便把满的指针块写回磁盘。总之,当指针块几乎为空时,一系列短期的临时文件就会引起大量的磁盘I/O。

一个可以避免过多磁盘I/O的替代策略是,拆分满了的指针块。这样,当释放三个块时,不再是从图4-23a变化到图4-23b,而是从图4-23a变化到图4-23c。现在,系统可以处理一系列临时文件,而不需进行任何磁盘I/O。如果内存中指针块满了,就写入磁盘,半满的指针块从磁盘中读入。这里的思想是:保持磁盘上的大多数指针块为满的状态(减少磁盘的使用),但是在内存中保留一个半满的指针块。这样,它可以既处理文件的创建又同时处理文件的删除操作,而不会为空闲表进行磁盘I/O。
对于位图,在内存中只保留一个块是有可能的,只有在该块满了或空了的情形下,才到磁盘上取另一块。这样处理的附加好处是,通过在位图的单一块上进行所有的分配操作,磁盘块会较为紧密地聚集在一起,从而减少了磁盘臂的移动。由于位图是一种固定大小的数据结构,所以如果内核是(部分)分页的,就可以把位图放在虚拟内存内,在需要时将位图的页面调入。
3.磁盘配额
为了防止人们贪心而占有太多的磁盘空间,多用户操作系统常常提供一种强制性磁盘配额机制。其思想是系统管理员分给每个用户拥有文件和块的最大数量,操作系统确保每个用户不超过分给他们的配额。下面将介绍一种典型的机制。
当用户打开一个文件时,系统找到文件属性和磁盘地址,并把它们送入内存中的打开文件表。其中一个属性告诉文件所有者是谁。任何有关该文件大小的增长都记到所有者的配额上。
第二张表包含了每个用户当前打开文件的配额记录,即使是其他人打开该文件也一样。这张表如图4-24所示,该表的内容是从被打开文件的所有者的磁盘配额文件中提取出来的。当所有文件关闭时,该记录被写回配额文件。

当在打开文件表中建立一新表项时,会产生一个指向所有者配额记录的指针,以便很容易找到不同的限制。每一次往文件中添加一块时,文件所有者所用数据块的总数也增加,引发对配额硬限制和软限制检查。可以超出软限制,但硬限制不可以超出。当已达到硬限制时,再往文件中添加内容将引发错误。同时,对文件数目也存在着类似的检查。
当用户试图登录时,系统核查配额文件,查看该用户文件数目或磁盘块数目是否超过软限制。如果超过了任一限制,则显示一个警告,保存的警告计数减1。如果该计数已为0,表示用户多次忽略该警告,因而将不允许该用户登录。要想再得到登录的许可,就必须与系统管理员协商。
这一方法具有一种性质,即只要用户在退出系统前消除所超过的部分,他们就可以在一次终端会话期间超过其软限制;但无论什么情况下都不能超过硬限制。