一个文件系统的空间管理,常见的技术大致有两种,bitmap和tree方式。
bitmap是将文件系统所有管辖的空间细化成block(windows叫cluster),每一个block对应一个二进制位,两种状态分别表示自由/已分配。将这些二进制位集合在一起,就是bitmap。当需要分配空间时,在bitmap中查找连续的自由位,分配后,再置成已分配就可以了;释放时,将对应位置为可分配即可。
tree方式是以extent的记录来描述自由/已分配空间的状态,如果以表示自由空间的tree来说,有可能是由一些"{可分配起始位置,可分配大小}"的记录组成的数据表。需要分配空间时,可以就某种优先原则查找可分配的自由空间段,分配后,重新调整树即可;释放时,重构记录,重构树即可。
上述两种模式在应付小容量的文件系统时基本问题不大,尤其是bitmap模式,以常见的4K块大小为例,在1T的文件系统上,位图的大小为32M(1T/4K/8),在内存中还是可以应付得过来,释放时效率的影响也不大。tree模式,虽然运算的负载较bitmap重了些,但好在文件系统容量不大,片断数量多数也在可接受范围内,整体性能影响也较小。
当文件系统越来越大,上述两种空间管理模式对效率的影响就开始突显,例如,在一个16T的文件系统上,如果还是4K的文件系统块大小,则bitmap的大小将大到1G,如果文件系统全部载入内存,一来内存负担太重,二来很难及时全部回写磁盘,在应付突然断电之类的问题上,要消耗巨大的资源(设计时也麻烦得多)。同时如果某个文件分配得很散乱,分配或释放时都会涉及大量随机IO的bitmap操作,导致io性能极低。如果在这么大的空间内想找到一个自由空间点,最差情况需要遍历1G的位图空间,也似乎也是很低下的模式。
tree的模式会综合一点,通常可以比bitmap消耗内存少一些,同时可能有记录合并的情况,所以,在查找可分配空间上不会因快用满性能明显下降。但释放空间、分配空间,会导致树结构的不断调整,树越大,这些负荷也越大。还有,最麻烦的是,分配还是释放还是无法保证连续记录,在磁盘IO方面,仍然无法避免随机io带来的低效(不过,优秀设计过的树结构还是有较大提升空间,以实现最大程度掩盖上述缺点)。
说完上述两种常见空间管理,显然是为ZFS铺垫的。
ZFS不同于bitmap和tree的空间管理,它是第三种,极少有文件系统采用的一种空间管理方法。
第一层:将所有需要管理的空间均匀分为不超过200个(源码中define的常量)的相同容量的小段,每个段只可接受2^N。也就是说把全空间除以200,得到的值向上趋近至2^N,就用这个大小对全空间进行切分,每一个分配空间叫一个metaslab。比如一个150G的全空间,除以200是750M,就向上趋近于2^N,即1GB,得到150个metaslab,每个大小为1GB。
metaslab是化整为零的第一步,每个metaslab都对应着单独的空间管理记录。(这样的好处是全局考虑释放、分配的情况会少很多)。
在ZFS中,一个metaslab的分配情况对应一个object,简单的理解,就像对应了一个文件(mos中的某个元文件)。其内容就是分配情况。如果没有分配空间(即全部空间可用),就不用为其分配空间记录表,也不用为其分配元文件。
第二层:每个metaslab中用位图表的方式记录:本metaslab中连续的1扇区的片断有多少个、连续的1K的片断有多少个、连续的2K的片断有多少个、4K,8K、16K,..1G、2G等连续片断有多少个。以便于在分配时,快速确定本metaslab有没有最优分配片断。
第三层:每个metaslab用流水账(space map)的方式记录本metaslab的io日志,所有的释放/分配都在这个账本的尾部续写。当本metaslab需要分配/释放空间时,先按时间顺序读入这个流水账,读完后,就生成了本metaslab的真实分配位图,再在内存中进行分配就可以,当达到一个事务节点时,将内存中的摘要信息(第二层)和正好在内存中顺便合并后的流水账信息回写到磁盘上(space map entry可以视情况合并,老的记录也可能优先合并了,所以不会特别大)
这样的好处至少在于:
1、整个文件系统的空间管理单元很精简,不会因文件系统特别大,或因文件系统快用完了就变得臃肿。空间管理更优秀地匹配了真实复杂度,正如文件系统刚开始的时候,空间管理非常简单;快用满时,也从复杂变得简单(分配融合,记录更少了),这是合理的。
2、化整为零,空间的分配优先在同一个metaslab中进行,实际上,相当于利用连续的小磁盘空间进行最有效的当前事务管理,提高了管理效力(与之相对的bitmap,用户可能只需1M空间,但文件系统驱动得读进所有bitmap,其他不相关的部分几乎是无用负载)
3、流水账方式的记录,简化的树操作。zfs把树的操作部分,全部放在内存中处理,磁盘空间上除了位图方式记录的片断表,就是顺序IO记录。这样减少了与磁盘IO的交互次数(因树触发的随机数据变更是最要命的),提高了文件系统性能。
唯一感觉缺点的是(张宇www.datahf.net注:未做详细实验,仅凭理论推断),每个metaslab分配时,都需要在内存中重构树,在简单应用时,运算负载会较传统文件系统更大。可简单应用,其实也无所谓运算负载稍重,反正可能cpu,内存都闲着。
理论部分就是上面,再图文并茂下,直观透视。
[root@localhost case4]# zdb -l /dev/nbd0 -------------------------------------------- LABEL 0 -------------------------------------------- version: 5000 name: ‘case4‘ state: 0 txg: 4 pool_guid: 4712723554953817788 errata: 0 hostname: ‘localhost‘ top_guid: 10025130926649767584 guid: 10025130926649767584 vdev_children: 2 vdev_tree: type: ‘disk‘ id: 0 guid: 10025130926649767584 path: ‘/dev/nbd0‘ whole_disk: 0 metaslab_array: 37 metaslab_shift: 28 ashift: 9 asize: 32207536128 is_log: 0 create_txg: 4 features_for_read: com.delphix:hole_birth com.delphix:embedded_data -------------------------------------------- LABEL 1 -------------------------------------------- version: 5000 name: ‘case4‘ state: 0 txg: 4 pool_guid: 4712723554953817788 errata: 0 hostname: ‘localhost‘ top_guid: 10025130926649767584 guid: 10025130926649767584 vdev_children: 2 vdev_tree: type: ‘disk‘ id: 0 guid: 10025130926649767584 path: ‘/dev/nbd0‘ whole_disk: 0 metaslab_array: 37 metaslab_shift: 28 ashift: 9 asize: 32207536128 is_log: 0 create_txg: 4 features_for_read: com.delphix:hole_birth com.delphix:embedded_data -------------------------------------------- LABEL 2 -------------------------------------------- version: 5000 name: ‘case4‘ state: 0 txg: 4 pool_guid: 4712723554953817788 errata: 0 hostname: ‘localhost‘ top_guid: 10025130926649767584 guid: 10025130926649767584 vdev_children: 2 vdev_tree: type: ‘disk‘ id: 0 guid: 10025130926649767584 path: ‘/dev/nbd0‘ whole_disk: 0 metaslab_array: 37 metaslab_shift: 28 ashift: 9 asize: 32207536128 is_log: 0 create_txg: 4 features_for_read: com.delphix:hole_birth com.delphix:embedded_data -------------------------------------------- LABEL 3 -------------------------------------------- version: 5000 name: ‘case4‘ state: 0 txg: 4 pool_guid: 4712723554953817788 errata: 0 hostname: ‘localhost‘ top_guid: 10025130926649767584 guid: 10025130926649767584 vdev_children: 2 vdev_tree: type: ‘disk‘ id: 0 guid: 10025130926649767584 path: ‘/dev/nbd0‘ whole_disk: 0 metaslab_array: 37 metaslab_shift: 28 ashift: 9 asize: 32207536128 is_log: 0 create_txg: 4 features_for_read: com.delphix:hole_birth com.delphix:embedded_data
本文出自 “张宇(数据恢复)” 博客,请务必保留此出处http://zhangyu.blog.51cto.com/197148/1862811
原文:http://zhangyu.blog.51cto.com/197148/1862811