如果仅仅是SSD的使用者,一定不会在意在SSD内部居然还存在一个复杂的软件层Flash Translation Layer(FTL)。其实就是这个FTL才是SSD固态硬盘的软件核心技术。正因为有了FTL,NAND Flash才能被当成硬盘来使用;文件系统才可以直接把SSD当成普通块设备来使用。由于FTL是SSD设计厂商最为重要的核心技术,因此,没有一家厂商愿意透露这方面的技术信息,并且也一直没有业内的技术规范、标准存在。
FTL的重要程度在于决定了一个SSD的使用寿命、性能和可靠性。一旦FTL出现问题,那么就会导致数据读写发生错误,更为严重的是SSD盘无法被访问。优秀的FTL不仅能够提升Flash存储的使用寿命,而且还可以最优化读写性能。因此,在Flash固态存储中,FTL是一个最为重要的管理NAND Flash的软件层。
在学术界,这十年来有很多文章在讨论如果实现一个高效的FTL,例如,在有限硬件资源的环境下如何实现mapping?如何实现buffer的管理?如何实现高效的Garbage Collection?如何实现磨损均衡Wear-leveling?如何实现NAND Flash芯片之间的数据冗余(RAID on Chip)?很多算法的提出非常具有建设性和现实意义,对工业界具有很好的指导价值。
这里主要想谈一下FTL内部mapping的机制。从文章《采用NAND Flash设计存储设备的挑战在哪里?》了解到基于NAND Flash研制存储设备是有很多挑战的,最大的问题在于NAND Flash不能像内存那样随意的写入。NAND Flash在Page页写入之前必须要将Page页所在的Block块擦除。如果研制SSD的时候严格按照这个准则,那么设计开发出来的SSD是不能用的。其一,按照这种方式进行写操作,写入的性能将会很差,其bottleneck限制在块擦除上(块擦除时间在ms级);其二,不断的对同一Block块进行擦除操作,那么该块将会在短时间内磨损写坏,并且极易导致存储在该块上的数据丢失。因此,在设计SSD时最主要的任务就是解决NAND Flash的这种“写时擦除”问题。
技术是相通的,在90年代提出的Log-structured File System(LFS)思想和NAND Flash简直是天生一对。当初设计Log-Structured File System最主要的想法是利用机械磁盘出色的顺序写性能,避免糟糕的随机写问题。Log-structured File System在机械硬盘的时代有一定的应用局限性,问题在于采用log数据布局的方式之后,读性能变得很差。因此,只有在大块数据读写(对象存储)的环境下,log-structured File System才变得合情合理。在NAND Flash介质上,不存在机械硬盘随机读写的问题,因此,log-structured的数据布局方式不会引入任何性能问题,反而能够解决NAND Flash的“写时擦除”问题。
采用Log-structured的方式之后,NAND Flash可以采用out-of-place的数据更新方式。所有的数据更新都不会写入原来的page页,而是重映射写入一个新的Page页。在这个思路的引导,很显然所有NAND Flash的存储资源可以按照物理Page页的方式管理起来,而用户可见的空间则是一个连续逻辑Page页连接起来的地址空间。FTL的一个关键任务就是建立逻辑Page和物理Page之间的映射关系,并且在数据写入时重新分配物理Page页。在这种机制的支撑下,SSD的写性能可以大为提高,写延迟可以控制在200us的级别。
引入log-structured的机制之后,逻辑page和物理page之间存在映射关系,FTL负责物理page页的分配。考虑到每个Block块都是有擦除寿命的,因此,如果想要提升SSD的整体使用寿命,那么需要将块擦除次数均衡到所有块上去。这个工作就交给了FTL中的块分配器。均衡擦除次数这个工作其实是挺麻烦的事情,其最大的挑战在于记录每个块的擦写次数,并且这些信息需要持久化存储。
众所周知,log-structured数据布局方式最大的问题在于垃圾回收(garbage collection),由于page页从来不会被in-place-update,因此,当一个page被重映射之后,老的page页就会变成无效,等待Garbage Collection回收该页。在NAND Flash中,GC最大的挑战在于以块为单元进行擦除,而不是Page页。换句话说,GC需要将一个Block块中的所有Page页同时回收,这个限制导致GC在回收一个Block的时候会进行数据迁移操作。过多的数据迁移操作会影响SSD的使用寿命,并且会影响到整体的读写性能。因此,优化Garbage Collection成了FTL最头疼的一个问题。最容易想到的一个优化方法是将冷热数据分开存储到不同的Block块中,这样在数据回收的时候,可以尽最大可能减少有效数据的迁移。
Log-structured File System为NAND Flash的FTL设计提供了一个非常好的思路。但是,要想在SSD这样一个硬件资源非常有限的平台上实现FTL的所有功能还是很有挑战的。举个例子,log-structured的方式是需要进行Page页映射的,映射操作需要建立映射表。如果内存太小,那么对映射表的大小就提出了需求。假设一个SSD具有1TB的容量,那么如果采用4KB Page映射的方式,每个page映射需要4字节描述,那么至少需要1GB的内存容量来存放映射表。在嵌入式系统中,1GB的内存容量是庞大的。因此,为了避免过多的占用内存容量,拍脑袋可以想到Block映射的方式。假设一个Block容纳128个Page页,那么一下子可以将映射表容量缩减到原来的1/128。但是这种Block映射的方式效率实在太低,会导致大量的数据迁移,从而缩短了SSD的使用寿命。
解答:如果我们把LBA和PBA都设置成page大小,这也叫做page-level mapping,这和我们写入颗粒一致,很灵活。但这么小的粒度会带来一个问题:逻辑对应表太大!想象一下,我们有个64GB的Die,每个page只有4KB,我们的对应表需要64*1024*1024 * 4 /4 = 64MB!这个绝对不能接受。那么按照block,也就是block-level mapping呢? 会不会好些呢?至少占用空间好了很多,但是因为写入时不清楚page情况,往往要整块擦除,效能会大大下降。有没有更好的办法呢?实际使用中常用的是log-block mapping,它从我们现代的log文件系统中学到经验,也充分利用了page和block的不同特性。
所以,为了减小映射表的容量,一个比较可行的方式是采用Hybrid映射方式。
Hybrid-level mapping的思想是将映射操作分成两级。第一级是data-log,所有数据首先写入log,当log写满之后,再将log中的数据合并至data-block;第二级是data-block,用来存放从log中合并过来的数据。对于data-log,由于数量有限,因此可以采用page-level mapping的方式;对于data-block,由于存储容量比较大,因此,可以采用block-level mapping的方式。Hybrid-level mapping可以很好的平衡内存使用和mapping效率之间关系,因此,学术界也对此提出了很多优化的方法。
其中,一个比较有意思的方法是locality aware的hybrid-level mapping思想,其原理如上图所示。从结构上讲,其大致可以分成传统Hybrid-level mapping的双层结构。写入的数据首先进入data-log。不同的地方是,data-log被分成了random-log-buffer和sequential-log-buffer。写入的数据根据locality-detector被分流至random-log-buffer或者sequential-log-buffer。其中random-log-buffer采用page页映射的方式,sequential-log-buffer直接采用block映射的方法,这样可以进一步降低内存使用量。当log-buffer中的数据满了之后,需要合并到data-block。合并的方法和传统的相同,被分成switch、partial-merge和full-merge。
FTL是NAND Flash存储的底层核心技术之一,由于NAND Flash本身存在很多问题,导致FTL的设计、实现都会存在很多的挑战。上面只是简单的阐述了一下FTL中mapping的一些棘手问题和一些解决思路,抛砖引玉,揭开了神秘面纱,往里面瞅上了一眼。这一看其实会发现,FTL虽小,但是难度丝毫不比一个文件系统小。
和传统磁盘相比,Nand Flash存储设备存储延迟低、功耗低、更高的存储密度、抗震型号更好和噪声低。但是,由于Nand Flash的特性影响(读写擦的单位不一致,每个块有P/E次数限制),Nand Flash不能直接通过简单的接口转换就拿来使用。所以我们需要在Nand Flash上增加一个管理软件FTL(Flash Translation Layer)进行管理,对外就是一个黑盒子,上层应用可以通过逻辑地址来对这个黑盒子进行访问。
图1
异处更新(out-of-place Update)。正如之前所说,Nand Flash编程操作只能把存储单元从1变为0,所以在重新编程之前需要进行擦除操作。而且编程以页为单位,擦除以块为单位(一个块包括多个页)。如果使用同处更新(in-place update),就是把同逻辑地址重复更新到同样的位置上,那么每一次更新,都需要先进行一次擦除操作。由于擦除操作耗费时间和对Flash有损伤,所以一般FTL使用异处更新,把更新的数据映射到一个新的位置上。
如下图,上层应用先写逻辑地址0、1,FTL把数据映射到Nand Flash的物理块0、1页上,然后上层应用又写逻辑地址0,此时物理块0第0页不能重新编程,所以FTL把数据存放在物理块0的第2页上。
图2
P/E次数有限制。之前有提到,Nand Flash每个块是有擦除次数限制的,在擦除一定次数后,这个块会变得不稳定,编程进去的数据容易出错,甚至会擦除失败。
性能更好。和传统机械硬盘不同,Flash存储是没有机械设备的,比如说不需要寻道,对所有的地址访问开销都一样,特别是在随机读性能上,SSD远远好于传统机械硬盘。按这个道理,Flash设备随机访问和顺序访问的速度是一样,但现实上,Flash支持Cache操作,在顺序访问中可以提前把下一个页的数据读取放到内部寄存器中,可以更快响应读请求。所以在顺序访问上速度要比随机访问要快的。
读、写速度不一致。如之前文章描述的,把电子从浮动门中吸进去(写操作)比检测浮动门电场状态(读操作)要耗时。所以FTL在管理时,尽量减少写和擦除的操作。
自我解答:我认为F2FS自带了FTL的功能,不需要传统的FTL的转换,可以直接操作raw flash设备。
因为F2FS是为flash文件系统专门设计的,而对于传统的磁盘文件系统不是为Flash而设计的,如果直接在Flash上运行会很快使Flash局部老化而丢失数据,或崩溃。另外由于FLASH的块比较大,如果直接映射成块设备的话,空间利用率低。