传统文件系统与NoSQL分布式存储的块存储技术对比(1)

时间:2021-02-03 05:15:27

    本文第一部分介绍经典文件系统ext3的块存储,第二部分介绍一个NoSQL分布式存储系统的块存储。

    ext系列文件系统是linux的土著文件系统,历经4个版本,最新是ext4,在linux 2.6.28内核正式引入,目前比较新的linux发行版都已经把ext4做为默认文件系统。下面先看看ext3的数据块存储结构,而ext4是对ext3的继承与优化,核心结构基本类似,同时也对ext3的提供向下兼容,后面再讨论它们的区别。 

    首先看看ext3的文件系统的结构图:

传统文件系统与NoSQL分布式存储的块存储技术对比(1)

    ext3整体结构还是清晰明了:

    1)引导块,主要是给系统引导的时候用的,包括512字节的MBR和64字节的分区表,余下的是保留区间。

    2)块组部分,则是由ext3文件系统管理的区域,块组编号从0开始。每个块组都包含data block bitmap、inode bitmap、inode table以及data block table(少数块组会有super block和gdt(gdt包含了文件系统所有块组的块描述符),但是文件系统一般只使用块组0的super block和gdt,其他块组的super block和gdt只是在一些时间点上进行备份,以防块组0崩溃了可以恢复到一个比较一致性的状态)。 

    块大小、每个块组包含的块数目、块组内inode table和data block table都是在创建文件系统的时候就设定好了。所以在文件系统的使用过程中根据给定的inode number(inode number从0开始编号,一直单调递增1),可以快速定位到所属的块组和在该块组的inode table里面的偏移量。同理给定block number(block number也是从0开始编号,一直单调递增1),可以快速定位到所属的块组和在该块组中data block table的偏移量。可以看到这种线性的组织方式是静态的,从文件系统建立那一刻就分配好了(不过由于ext3有一些保留块,这些保留块也为文件系统的resize提供了一定支持,主要是为了保存更多的gd)。

    下面再看看ext3的数据块索引:

传统文件系统与NoSQL分布式存储的块存储技术对比(1)

 

    ext3的inode中有一个重要的数据成员i_block(其实上面这个图如果横着展开的话,其实是一颗树型结构),是一个包含15个32位整数的数组,其中前12个元素直接保存的存储文件数据的block的block number;第13个元素保存的block number指向的block里面保存的是block number数组,而非文件数据,简称一次间接索引。同理,第14个元素保存的二次间接索引,第15个元素保存的是三次间接索引,此机制保证了ext3最大支持的单个文件大小为4TB多一点(假设block size是4K,那么最大的文件大小=4K*12 + 4K/4*4K + 4K/4*4K/4*4K+4K/4*4K/4*4K/4*4K ~= 4TB,但是实际上由于ext3实现的限制,为了使得每个文件包含的磁盘扇区数不超过2^32个,所以在block size为4K的情况下,ext3的最大文件大小实际上只有2TB)。如果文件系统的block size是4K,那么只要不大于48K,都只使用前12个元素,否则就会用到后面的间接索引。试想如果要访问一个2G文件的最后4KB,那么将要经历二次索引和一次索引,如果包含索引的数据块不在pagecache中,那么将发生多次IO读,效率有点低。

    在ext4中,ext4的inode依然保留了i_block这种结构,而且提供向前兼容,同时也提供了更具弹性的extend分配方式(最多有4个extend,但是extend也可以是多级树形索引组织,一个extend由逻辑块号、块数和物理块号标识),只是extend的存储是重用这个i_block的存储空间的,也就是ext4兼容两种分配方式。对比ext3基于三级间接索引的分配机制和ext4的extend分配机制,首先在元数据规模上就有很大区别。试想如果一个4G的大文件,且文件系统block size是4K,则文件需要100w个block存储,也就是需要保存100w个block number,每个block number是4个字节,那么就至少需要4M的元数据了,这个还不包括一次和二次间接索引需要的数据块。其实问题很简单,在这种分配方式下的索引数据的熵值永远>=4/4K,即千分之一。如果采用extend分配方式,元数据规模将大大降低,因为一个extend可以标识很多块连续的数据块。

    以上两个图的结构基本上是ext3的on disk结构(也就是物理磁盘上实实在在存储的信息),至于in memory的结构基本上跟这个on disk的结构一一映射,只是做了少许封装。个人认为ext3/4的精髓在于分组管理和bitmap应用(这里暂时不讨论ext3/4的journal部分,因为jbd严格上来说不属于具体的文件系统,而是一个通用的文件系统日志管理模块,jbd本身的复杂度一点不比ext3简单),一般文件的数据都优先存储在同一个块组里面,这样就带来了IO的聚集特征,对性能有好处。其次简单的bitmap既节省了元数据的规模计算也比较简单。由于简单的物理结构,所以必定带来不怎么高的性能,幸好inode cache和dentry cache和pagecache的充分利用使得ext3在一般情况下性能还可以。

    使用ext3文件系统往往有这样一种纠结:该文件系统对小文件的物理存储本身是高效率的,从i_block的构造看出来,但是小文件带来了大量索引开销(inode存储和查找)却起到了相反的作用;物理存储本身对大文件却是低效率的,因为要经过多次索引,且数据块不连续的概率很大,但是使用大文件索引开销却比较低。从实际的应用角度上看,大量小文件的应用是真正的性能杀手,特别是32位系统以前经常会由于大量小文件而消耗了大量low memory,导致内核由于低内存不足而产生oom-killer现象,所以一般都对小文件进行封装成大文件,然后动态映射大文件访问,只要内存足够大,间接索引块的pagecache命中率还是很高的。

    ext4是对ext3的继承和优化改进,主要打破了ext3在磁盘容量、文件大小、子目录数等等的硬限制。但是为了向前兼容,核心的ondisk数据结构基本没什么大改,主要是在结构尾部增加了一些细化计量和加速字段,ext4在功能算法和in memory结构组织方面有比较大的改进。