基本概念
根据硬件上存储原理的不同,Flash主要可以分为NOR Flash和NAND Flash两类,在不少方面有不同,但大体的Flash主要特性是基本一致的。我们在文中的举例均以NAND Flash为例。
FTL译为闪存转换层,是Flash Memory与Device Controller之间的连接关系。在广泛使用的SSD中都会内置FTL。事实上几乎所有的应用NAND Flash的设备都必须配备FTL,通常FTL由这些设备的固件提供实现。
FTL存在的本质原因是因为Flash与磁盘有非常多的不同。
Flash是一种非易失性的存储器,在嵌入式系统中通常用于存放系统、应用和数据等。在PC系统中,则主要用在固态硬盘以及主板BIOS中,另外,绝大部分的U盘、SDCard等移动存储设备也都是使用Flash作为存储介质。因此,Flash是一种非常常见的存储介质。与传统的磁盘相比,Flash具有质量轻、能耗低、体积小、抗震能力强等的优点。
但是,Flash也有一些自己的特性,比如:
需要先擦除再写入。Flash写入数据时有一定的限制,他只能将当前为1的比特改写为0,而无法将已经为0的比特改写为1,只有在擦除的操作中,才能把整块的比特改写为1。
块擦出次数有限。Flash的每个数据块都有擦出次数的限制,擦写超过一定次数后,该数据块将无法可靠存储数据,成为坏块。
Flash中常见的NAND Flash特性如下:不对称的性能。读的性能最好,写性能次之,擦除性能最差。
读写基本单元是Page页,而擦除基本单元是Block块。
Block块内部只能采用顺序方式进行写入。
每次page页写的时候都需要进行擦除操作
块擦除有寿命限制。
因为Flash有这些特性,这些特性是磁盘所不具备的。最关键的是这些特性是不能通过简单的接口转换绕过的。传统以及目前常用的众多文件系统,例如FAT文件系统、EXT文件系统等等,都是针对磁盘设计的,而不是针对Flash设计的,因此不能直接操作Flash。为了不加重操作系统和文件系统的负担,SSD提供了FTL这一层次的系统进行中间转换。
所以简单来说,FTL的作用就是解决负载均衡并且将SSD或是其它一些NAND Flash设备包装成适合传统文件系统操作,大小合适的块设备。FTL的设计和实现面临着很多的问题和挑战,实际上是一个非常复杂的系统,是SSD固态硬盘的软件核心技术,没有一个统一的最优解决方案。
一些算法
Mapping机制
NAND Flash不能像内存那样随意的写入,在Page写入之前必须要将Page页所在的Block块擦除,如果研制SSD的时候严格按照这个准则,那么设计出来的SSD是不能用的。原因在于,按照这种方式进行写操作,写入的性能将会很差,其性能瓶颈限制在块擦除上,而块擦除时间在毫秒级别。另外,不断的对同一Block块进行擦除操作,那么该块将会在短时间内磨损写坏,并且极易导致存储在该块上的数据丢失。因此,在设计SSD时最主要的任务就是解决NAND Flash的这种写时擦除问题。
常用的设计思路来源于90年代提出的LFS(Log-Structured File System)思想。设计LFS的最初想法来源于利用机械硬盘出色的顺序写性能,避免糟糕的随机写问题。但是LFS在机械硬盘的时代有一定的应用局限性,问题在于采用log数据布局的方式之后,读性能变得很差。在NAND Flash介质上,不存在机械硬盘随机读写的问题,因此,log-structured的数据布局方式不会引入任何性能问题,反而能够解决NAND Flash的写时擦除问题。
采用LFS的方式之后,NAND Flash可以采用out-of-place的数据更新方式。所有的数据更新都不会写入原来的page页,而是重新映射写入一个新的Page页。NAND Flash的存储资源按照物理Page页的方式管理起来,用户可见的空间则是一个连续逻辑Page页连接起来的地址空间。FTL的一个关键任务就是建立逻辑Page和物理Page之间的映射关系。并且在数据写入时重新分配物理Page页。在这种机制的支撑下,SSD的写性能可以大为提高,写延迟可以控制在200微秒的级别。
引入LFS的机制后,FTL负责物理page页的分配,考虑到每个Block块都是有擦除寿命的,因此,如果想要提升SSD的整体使用寿命,那么需要将块擦除次数均衡到所有块上去。这个工作就交给了FTL中的块分配器。每个块的擦写次数都需要持久化存储。
GC机制
类LFS数据布局方式最大的问题在于垃圾回收,由于Page页从来不会被in-place-update,因此当一个page被重映射之后,老的page页就会变成无效,等待Garbage Collection回收该页。在NAND Flash中,GC最大的挑战在于以块为单位进行擦除,而不是Page页。换句话说,GC需要将一个Block块中的所有Page页同时回收,这个限制导致GC在回收一个Block的时候需要进行数据迁移操作。过多的数据迁移操作会影响SSD的使用寿命,并且会影响到整体的读写性能。一个常用的优化方法是将冷热数据分开存储到不同的Block块中,这样在数据回收的时候,可以尽最大可能减少有效数据的迁移。
TRIM命令
TRIM指令是微软联合各大SSD厂商所开发的一项技术,属于ATA8-ACS规范的技术指令。
TRIM是告诉NAND闪存固态存储设备要擦除哪些数据的SATA接口指令。当相关页面的数据可以被覆盖时,操作系统会发给SSD一个TRIM指令。SSD控制器等到主机开始删除和再次写入操作的时候,执行安全擦除操作。因为在写入操作过程中不用花时间去擦除原本的数据,写入速度要快得多。
我们在操作系统中删除一个文件时,系统并没有真正删除这个文件的数据,他只是把这些数据占用的地址标记为空,即可以覆盖使用。但是这只是在文件系统层面的操作,硬盘本身并不知道哪些地址的数据已经无效,除非系统通知他要在这些地址写入新的数据。在HDD上本无任何问题,因为HDD允许覆盖写入,但到SSD上问题就来了,闪存不允许覆盖,只能先擦除再写入,要得到空闲的闪存空间来进行写入,SSD就必须要进行GC操作。在没有TRIM的情况下,SSD无法事先知道那些被删除的数据页已经是无效的,必须到系统要求在相同的地方写入数据时才知道那些数据可以被擦除,这样就无法在最适当的时机做出最好的优化,既影响GC的效率(间接影响性能),又影响SSD的寿命。
总结——解决的问题
地址映射管理
Flash设备对外是一个黑盒子,里面集成了NAND Flash和FTL等,上层应用使用逻辑地址来访问,FTL把逻辑地址映射到不同物理地址上,管理着每个逻辑地址把最新的数据存放的物理地址。
垃圾回收
随着数据的写入,闪存设备有些块的部分数据已经无效了,需要把有效的数据从块上搬走。然后擦出用来接受的新的数据。
磨损均衡和坏块管理
因为每个块的P/E次数是有限的,某些块可能被重复使用而损坏了,而有些块数据很少被访问,所以一直没有进行操作过。为了避免这种情况,FTL加入磨损均衡的功能,大致是通过控制垃圾回收和空块池的管理,从而平衡每个块的使用次数,最理想是所有块一起达到磨损阈值。由于Flash本身就存在部分坏块,在使用的过程中部分块会变坏,所以FTL在管理的时候需要避开这些无用块,把使用后变得不稳定块上的数据及时拷贝到稳定位置。
纠错
由于NAND Flash工艺,不能保证在生命周期中保持可靠性能,并且NAND Flash在出厂时也会自带一些坏块。因为在使用过程中,为了保证数据的可靠性,NAND Flash控制器中一般都内置了坏块管理策略。如果操作时序和电路稳定性不存在问题的前提下,NAND Flash出错一般不会造成整个Block或Page出错,而是整个Page中某一个或者某几个bit出错。
在NAND Flash的处理中,使用专用的校验方法。在之前SSD一般采用BCH编码保护数据正确性,现在更多的使用LDPC算法。不管是什么编码算法,目的都是为了保证数据正确性,当出现少量错误时通过算法给予修正,如果错误超出编码算法的可修正范围,就标记新的数据坏块,并结合坏块管理策略。