当前位置: 首页 > 网络应用技术

文件系统概述:性能指标,设计思想,可靠性保证

时间:2023-03-08 18:10:04 网络应用技术

  文件系统可能是操作系统中最复杂的片段。与内存管理和流程计划相比,问题涉及更多问题,并且该软件需要帮助硬件解决方案。com与网络IO相比,文件io不是权威的,它可以谈论来自IO堆栈的书籍底部。IO堆栈的顶部。

  本文不适合初学者,但适合审查作为初学者和采访聚会学习材料的材料。

  目前,最主流的存储硬件包括SSD(固体状态硬盘)和HDD(机械硬盘)。从本质上讲,SDD的速度是HDD的十到二十倍,成本是五到十倍HDD。

  在JD.com中搜索机械硬盘和固体硬盘,根据销售进行排名,选择前三名(2021/4/24),并感知到可感知的价格差异(忽略机械硬盘之间的差异以及实心之间的差异 -状态硬盘)))

  总结表格,每10GB的平均价格

  SEAGATE 4TB1.5西部数量1TB7.5 Seagate 2TB2.1三星1TB12西部数字1TB3.3 Kingston 480GB7.5 SeaGate 1TB3.3 Samsung 1TB23如果您想详细比较价格和容量,请参考此处。

  无论是HDD还是SSD,其管理组织表格基本上都是相同的,并且基于部门(部门),通常是512B或4KB。

  文件系统具有磁盘管理的另一个定义。该文件系统分配并记录磁盘的使用(有时也称为页面)。页面通常为4KB,8KB,16KB,32KB。

  诸如部门,街区和页面等术语有一些歧义。这是个人分类:这里:

  在下文中,您将尝试尽可能使用扇区和页面,而块的含义与页面相同。

  不幸的是,广泛地说,当前的硬件几乎无法提供。

  在任何时候电力耗电的情况下,大多数硬件都可以提供单个部门的原子写作;但是,也有一些硬件无法通过编写单个部门来保证。如果页面对应于多个部分,则将完整写入单个页面的完整写作。始终保证输入。对于更详细的案例,您可以检查此讨论:crash -are disk sector sector work work with artomic?

  另一方面,机械硬盘可能会损坏环路;对于坚固的硬盘,可能会损坏存储粒子。一些硬盘可以帮助我们解决这些问题,但有些磁盘不是。

  在最后一个方面,硬盘不能保证发给硬盘的多个操作(例如编写多个不连续的部分)的操作顺序。在任何中间状态下,这主要是由机械硬盘和固体/机械硬盘的缓存策略的优化策略引起的。

  这些问题,硬件制造商和文件系统正在尝试解决,有些问题已经取得了不错的成绩。对于软件开发人员,尤其是数据密集型软件开发人员(例如数据库),屏蔽硬件和操作系统之间的差异以及一致提供的差异,但是可靠的软件,这是不可避免的责任。

  这些“不可靠”带来的另一个启示是,我们可以使用模式系统(某些功能,例如页面缓冲区和日志系统)来操作文件以进行高性能。但是,这也将失去操作系统提供的一些可靠保证。

  在了解基础硬件组织之后,让我们看一下我希望通过文件系统提供的接口(即顶级API),最后结合顶层的要求和基础硬件,以了解如何实现文件系统系统系统需要解决困难。

  作为操作系统顶部的用户,我们希望文件系统可以提供

  对于操作系统和文件系统的开发人员,有不同的需求和注意事项

  了解需求之后,我们可以将请求量化为性能指标。

  文件系统中的两个主要变量是IOPS和吞吐量

  文件系统中有很多自变量,即使使用了场景。也是因为文件系统的使用方案非常大,因此性能测试非常复杂。它主要包括队列深度,并行线程,单个请求的数据大小,一种读写的方法

  通用文件IO基准工具(例如Crystaldiskmark 8)集中在前三个自变量(单个线程的队列的深度,线程数,单个请求的数据)和单个单个数据大小的数据大小上。请求是4KB整数整数。在阅读和写作方面,仅顺序阅读,写作以及随机阅读和写作(我不知道随机读取,写作和随机位置是否是块大小的整数倍数,我不知道如何随机)因此,硬盘的制造商和文件系统将承诺优化上述固定方案。但是在工程学中,需要更严格地测试其实际性能。

  文件系统管理硬盘的存储空间,并且内存系统必须管理内存空间。从总体上讲,文件系统将4K用作最小管理单元。此数据还具有一些论文支持。研究表明,系统中的大多数文件都小于4K。我们将文件系统的最小管理单元称为页面,有时也是一个块。

  文件系统需要管理硬盘空间,并且内存系统需要由内存空间管理。两者之间有许多相似之处。主要点是,细分市场和分页的思想相似。

  为了满足上述要求,我们通常将块分为这样的几类:

  inode是索引节点的缩写。在初始文件系统中,所有这些节点都放在数组中。我们基于投标访问特定的节点,然后访问相应的文件数据。所有基本文件系统现在都有一个inode结构来保存文件的元数据。

  每个Inode都有一个ID,我们通过ID找到相应的Inode节点。在目录数据,文件名和Inode号之间的映射关系,因此我们指定一个文件名来查找相应的Inode.t,由于Inode和File名称的解耦,一个Inode可以对应多个文件名。

  串联,文件名,inode和文件数据可能是这样的关系

  由于文件元数据和文件数据的脱钩,文件的类型具有更大的自由度,甚至我们可以创建一个新文件,但是该文件没有数据,或者数据在内存中。

  目录也是文件,其数据仅由文件系统读取和写入。数据主要是文件名的键值对和Inode ID。

  Inode的基本操作太多了,我们的设计和优化也围绕着这些操作。

  在简单的实现中,我们可以将固定区域设置为Inode块,并按顺序设置编号,并根据Inode ID找到相应的Inode。删除也是o(1)。应用新的Inode问题,因为Inode的数量不能无限地增加(因为固定了Inode块,长期以来已经划分了Inode的数量)。因此,要么穿越Inode块以查找空闲的inode,然后使用其他数据结构来管理空闲的Inode。

  如果我们使用B树,则以上三个操作基本上是O(1)。唯一的问题是复杂性,很容易遇到问题。

  当然,还有其他数据结构。除了上述三个基本操作外,我们还需要考虑Inode的可伸缩性及其自身的空间职业。例如,在上面的简单实现中,它没有可扩展性。B树具有良好的可扩展性,而不是简单地实现它,但是会有更多的额外空间(但还可以)。

  一个inode可以对应于多个文件名。我们调用此共享ID将文件数据作为硬链接共享。

  与硬链路相对应的是软链接。软件链接是一种特殊的文件类型。它的值是“链接文件的文件路径”。此文件路径可以是绝对路径或相对路径。因此,如果您通过软链接读取文件数据,则需要通过软链接文件的值找到相应的文件,然后找到对应于的Inode ID文件,然后...(省略)。它不如硬链接那么好。在同一时间,软链接不会增加Inode的参考计数,因此,如果删除了源文件,则软链接的文件将不会消失,但会失败。

  在文件系统中,每个块的大小都是固定的。只要您知道块的顺序,结合了块的大小,就可以轻松地计算任何偏移中的哪个数据块。

  在Inode中,某些字段记录文件数据的块。如果文件很小,那么这些字段就足够了。但是,如果文件很大,很明显,我们不能增加小文件的每个Inode结构的大小。

  为了解决这个问题,我们通常使用称为间接指针的技术。在Inode结构中,n个字段(通常是十二个)位置,并且记录了n个数据块在文件前的位置。场地。该字段还标记了一个块位置,但是该块存放不是文件数据,而是数据块的地址(我们称其为间接指针块,间接指针块),以便我们取消更多数据块地址以实现较大的文件。

  再次扩展这个想法,我们可以实现多层嵌套。间接指针块记录其他间接指针块以实现较大的文件。

  假设每个块的大小为4KB,并且块的索引为32位,即4Byte(可以索引16TB空间)。

  一个块可以记录$ 4KB div 4b = 1024 $块,最大文件为$ 1024 IMES 4KB = 4MB $。

  如果您使用第二级间接指针,则可以记录$(4KB div 4b)^2 = 1024^2 = 2^{20} $ block。最大文件为$ 2^{20} IMES 4KB = 4GB $。

  如果使用三级间接指针,则可以记录$(4KB div 4b)^3 = 1024^3 = 2^{30} $ block,最大文件为$ 2^{30} imes 4kb = 4tb $。对于普通用户来说,这基本上足够了。

  但是,不应低估这些间接指针块的消耗。对于第二级间接指针,如果我们记录4GB文件,我们需要额外的$ 4KB + 1024 imes 4kbapprox1mb $。对于三个级别的间接指针,您需要要为$ 4KB + 1024 IMES 4KB + 1024^2 IMES 4KBAPPROX 1GB $。这意味着,如果记录了一个大文件,则需要大约四分之一的空间来记录文件数据。

  为了减少这些间接指针块的数量(毕竟,这些块还消耗了硬盘的存储空间,右),我们还可以让间接指针块记录块的范围(类似于分段的内存管理),例如从520块到666块,从该文件中的数据。当然,还有许多其他方法并在这里解决问题。

  在简单的实现中,固定区域将分为Inode块。当然,这将限制文件总数。

  如果使用B树,则文件总数非常好。现在。因此,B树还可能需要其他数据结构来记录Inode ID。

  我们还可以使用链接列表来展开Inode块,单个搜索的复杂性将上升到O(n)。但是,也可以优化它。例如,链接列表上的单个节点非常大,导致内存中数组形式的n个small链接信息,复杂性也可能非常低。

  简而言之,这里的问题非常明显,解决方案和数据结构的选择和组合是免费的和多样的。

  对于目录,我们的主要吸引力是记录文件名和Inode ID的关键值对。在正常情况下,单个目录中的文件不多。我们以数组的形式保存钥匙值对,并通过遍历搜索数据。

  我们可以假设常规文件名不会超过8个字节(少于8个字节,带有0个补充),因此8个字节文件名+4个字节Inode ID用作组。售出一个单位空间)。块可以放置341.33键值对。

  如果我们想将更多文件放在目录中,考虑到目录也是文件,则问题与“无限文件”相同。无需重复。

  如果要支持无限文件名称,则有两个方案,也可以与片段和页面进行比较:

  细分:在每个记录的开头,记录文件名的长度(2个字节可以记录2^16^a字节,通常只有2^12^a字节),然后按照以下内容进行操作-up -up紧密。与带有n的文件名一起,最后4个字节为Inode id。或在没有2个字节的情况下标记长度,并使用字符串端(8 0)标记结束。

  打击:如果文件名超过8个字节,它占用了两个8+4空间。因此,我们如何记录文件条目占用多少单位空间?您可以标记字符串末端的末端。如果末端还没有结束,则下一个单元空间将延长。您还可以记录在单位空间开头占用多少个单位空间;单位空间的大小。

  我们还可以从间接指针中获得一些灵感,例如我们将长文件名称放在一个特殊的块中。全部,长文件名很小,而且性能也没有重大问题。

  我们都以上面的列表形式存储数据。您还可以使用其他数据结构,例如B树,链接列表等。

  总而言之,目录的数据结构也很清晰且简单,并且其设计也非常灵活。

  Bitmap的实现很简单:未使用哪些块。BitMap是一个可以实现此目的的简单结构。当使用时,我们可以通过Bitmap找到未使用的块。显然,这种性能并不是特别好。

  我们还可以从分段的想法中学习,以记录空闲块的范围。例如,1-20是空闲的,30-80是空闲的。

  我们还可以使用这些空闲块来记录“空闲块”,而无需使用其他数据结构。每个怠速块记录连续怠速块的长度,同时指向下一个连续的空格块。例如:编号:编号。1个块(连续下一个连续的闲置是空闲的,下一个空闲块是第30号) - > No. 30块(连续连续50个连续50个块是免费的,下一个空闲块为n)。

  无论哪种结构,我们也希望可以将文件数据存储尽可能连续,以便在阅读时会有更好的性能。

  在了解Inode和目录数据之后,我们查看是否创建了一个新文件,并编写一些数据,可能是哪种障碍涉及的过程。

  要总结,创建一个新文件,您需要编写2-N Inode块,0-N间接指针块,1-N BITMAP块,2-N数据块。即使系统可以在内存中准备所有块数据一次将其发送到硬盘,因为硬盘无法保证原子写作和写作的顺序,并且在电源故障的情况下,数据将是错误的。

  我们需要将如此多的块包装到交易中,以便实现此交易原子,并且我们可以从各种崩溃中恢复(主要是关闭电源和无线,没有人可以保存机床)。

  整个基本过程遵循“提前”规则,这意味着在任何写作操作之前,编写日志,然后写入实际数据。特别是,整个过程分为三个步骤:写入日志,提交和安装。

  写日志正在编写日志。日志中的主要内容是修改后的块数据和交易中块的位置。

  提交是日志末尾的标志,也是交易完成的标志。我们可以认为,在提交后,该消息已被安全地编写,并且该应用程序可以响应用户。

  安装发生在提交后的任何可能的时间,并且确实适用于文件系统的其他位置,并且这些块的数据即将编写块的位置。只要完成最终执行,就可以完成执行,甚至在安装过程中崩溃。

  如果系统在提交提交之前崩溃/关闭电源,则该程序不会对用户响应,并且该日志最终不会安装。它将安装。如果系统崩溃/电源关闭,则系统将重新输入日志,下次系统将在启动系统时重新编写。

  同时,多个程序可以同时向操作系统提交写作操作。如果每个程序的文件IO串行执行,则硬盘将反复启动IO完成的中断,从而带来多个CPU上下文切换。同时,硬盘本身不能全面发挥其自己的写作表现(例如SSD 1可以编写1M,但是操作系统和CPU 1MS最多提交至100K写作请求),并且无法优化随机写作表现(例如,由于HDD地址的地址)。因此,文件系统将始终将多个写入请求(过程 - >文件系统)合并到交易中(文件系统 - >硬盘驱动程序)。

  具体而言,合并方法相对多样,例如根据时间片进行分裂,每10毫秒中的请求合并;或根据书面数据的大小对其进行分配,每1MB编写一次;或灵感策略。

  一般而言,所有写作请求(例如用C语言的写功能调用)不会立即在磁盘IO中发生。从写功能返回并不意味着此写作操作已经成功。这意味着文件系统已经对此写作操作有所了解。只有从冲洗函数返回的,该写作操作就可以通过交易来处理。

  与数据库类似,文件系统中的每个事务也具有唯一的ID,并且ID将继续增长。此ID需要长时间保存。

  有些人可能会怀疑,为什么我们要强调单独提交的操作?写日志完成,不仅仅是日志的末尾吗?这是因为系统可能在令状日志过程中崩溃,然后我们可能不会能够区分硬盘上的数据。无论我们写它,还是硬盘惯性擦除留下的肮脏数据。因此,对于文件系统,有必要单独取出提交,这是非常重要的一步。

  因此,这里的核心问题类似于计算机网络中的某些问题:如何验证消息不会被篡改?最自然的方法是向消息添加验证代码。我们可以计算日志的哈希值并将其放在日志前面。

  仅编写了哈希值和日志,然后在安装可以通过之前的验证(哈希(log)==哈希值)。如果任何零件未编写或未完全编写,则无法批准验证。据认为,该日志没有提交,也不需要安装。

  提交后,数据尚未处于该位置。如果我们修改文件的1个字节,并在提交后,则跳过文件系统以检查磁盘的内容,它将发现文件已有没有更改。但是,如果我们通过文件系统读取此文件,我们会发现文件已更改。

  在阅读过程中,我们可以订购文件系统的页面缓存,因此根本不会发生硬盘io。如果没有页面缓存,我们将读取硬盘。硬盘,我们将检查要读取的块是否已更改并且尚未应用,也就是说,是否有有关此块的日志,尚未安装。并阅读数据。

  另一个安装的时间是系统启动时。由于文件系统需要知道当前事务ID,并且已修改了哪些块,但尚未安装。因此,最好做两件事两件事安装日志中的两件事并了解业务ID。顺便一提

  在上述方案中,最大的问题是文件的元数据通常相对较小,并且将其放入内存是没有问题的。从日志块上复制到Inode块并不是一个大问题。但是,文件的数据很大,并且可能不允许在内存中。从日志块复制到数据块还将带来非常严重的写作和性能问题。因此,优化通常会注意文件数据。

  诸如EX4之类的现代文件系统为其进行了优化。

  当我们了解一般文件系统中遇到的问题时,我们可以看到现代文件系统如何解决这些问题。那么它看起来像什么?哪些文件系统是经典且可用的?现在文件系统中使用了哪些新技术?

  我建议它在禁止的Linux文件系统下查看本文:EXT4及以后。知道Linux China具有它的翻译。尽管翻译的质量有些问题,但我们足以概述现代文件系统。这篇文章是在2018年9月写的。本文的这一部分是上面的摘录和概述。

  原始:https://juejin.cn/post/7121928829026697246