在《深入浅出SSD》的读书笔记的FTL主要业务博客中,简单介绍了FTL的映射的基本原理,和垃圾回收的基本原理。在FTL介绍章节中,FTL还做了其他很多工作,我个人理解主要分为两类,一类是优化(包括寿命优化和性能优化),一类是异常处理。以下做简单介绍
寿命优化 | 性能优化 | 异常处理 |
---|---|---|
TRIM | TRIM | 坏块管理 |
磨损平衡 | SLC cache | RD & DR |
坏块管理 | SLC Cache | |
掉电恢复 |
在机械硬盘的场景中,删除文件只是调整对应目录的元数据。并不会涉及到擦写文件对应的数据块本身。SSD上逻辑块和物理块的映射关系还是存在的,只有在后续系统再在相同的地方写入数据时,才会知道数据无效。
这在机械硬盘场景中无伤大雅,但是在固态硬盘场景中,会导致这些数据在后续真正再写入之前,这些物理块都会被认为是有效数据,在垃圾回收时不被回收,或者仍然被认为是有效数据而被搬移,导致写放大和影响固态硬盘的寿命。只有在知道数据无效之后,才会在垃圾回收的时候被回收。
针对这个场景差异,为了优化写放大问题,ATA命令中新增了TRIM命令,在用户删除文件时,OS会发送TRIM命令给SSD,SSD就会把这些数据块标记为无效,后续SSD就可以在垃圾回收时抛弃掉这些数据,可以避免做无谓的搬移。
SCSI有对应命令叫 UNMP,NVMe里则叫 Dataset Management
TRIM命令会影响FTL中的三张表
收到TRIM之后,固件需要实现如下处理流程。
1)清除L2P table为空地址。
2)清除VPBM上的有效页的位。
3)更新VPC的有效页个数。
4)重复上述环节,遍历每一个LBA。
下述是TRIM处理后,对GC处理流程影响。
GC处理。
1)根据新的VPC重新计算GC优先级——》
2)回收VPC最少的Block(不考虑磨损平衡)——》
3)擦除全是垃圾的Block。
磨损平衡是让SSD的每个闪存块的磨损(擦除 )次数都保持平衡。闪存块擦写次数超过一定的值,块就不那么可靠了,就变成坏块。过多的坏块会让SSD在保质期前挂掉。
1、不同集成度的SSD擦写寿命不同。
类型 | 寿命 |
---|---|
SLC | 十几万 |
MLC | 几千 |
TLC | 一两千次/几百次 |
2、数据按照更新的频繁程度不同,分为两类
一类是冷数据,不经常更新的数据。比如 OS数据,只读文件
一类是热数据,更新频繁的数据,会产生很多的垃圾数据,比如一些频繁更新的文档。
3、块按照擦写次数不同分为两类。擦写次数称为EC(Erase Count)
一类是年老块,擦写次数多。
一类是年轻块,擦写次数少。
主要分为两种。
一是动态磨损平衡(DWL, dynamic wear leveling)宗旨是把热数据写到年轻的块上。写新闪存块时,选EC小的。
二是静态磨损平衡(SWL, static wear leveling)宗旨是把冷数据写到年老的块上。以腾出冷数据原来所在的EC小的闪存块,把这些闪存块用于数据写入。
静态磨损平衡的一种选择是通过GC机制来做,即回收时不选择有效数据小的闪存块,而选择冷数据所在的闪存块。但这样的负面作用就是导致冷数据和热数据会混在同一个闪存块上,因为回收的闪存块上的冷数据被搬移到了其他的闪存块上,即写入了GC时读出来的数据。而这个其他的闪存块可能是用户用来写数据的闪存块,这就导致冷数据被混到了热数据上。
但是冷数据的地址中大部分仍然还是冷数据,可能会在GC时被搬移。导致写放大。
SWL写入冷数据到——》Block1
GC写入热数据到——》Block1
Host写入热数据到——》Block1
更进一步的策略就是做冷热数据分离,在静态磨损平衡时,用专门的闪存块来存放冷数据。这个闪存块不与用户数据,或者GC写入的数据混用。这样就这个冷数据的块就不会被GC挑选为源闪存块。(故而这里要区分 常规的GC和 带了静态磨损平衡的GC)
SWL写入冷数据——》Block1
GC or Host 写入热数据——》Block2
坏块分为出厂坏块(Factory Bad Block)和增长坏块(Grown Bad Block)。增长坏块为擦写磨损导致的坏块。
对出厂坏块而言,出厂数据默认全部是 0xFF,坏块会被厂商打上不同的标记用作区分。
对增长坏块而言,是以读写擦的形式反映出来。比如出现UECC,擦除失败,写失败等症状,都需要加入坏块表,都是坏块出现的症状。
坏块管理主要存在两种策略,略过策略和替换机制。
优劣比较
优点 | 缺点 | |
---|---|---|
略过 | 性能不稳定(并行度会发生变化)(p.s. 这里个人并不是太理解) | |
替换 | 并行度稳定 | 木桶效应,如果某个DIE质量较差,可用容量就受限于这个坏的DIE |
问题根因:
每次读,都会对其他字线 wordline 形成有点像轻微的写入,长此以往,会导致比特翻转(1->0)出错数超过ECC的纠错能力,就会导致数据丢失。
解决策略:
在读的次数低于某一个阈值之前,即比特发生翻转之前,对闪存块上的数据进行一次刷新。搬到别的闪存块上,以实现防患于未然。
解决实现:
FTL记录每个闪存块的读次数,每读一次,读次数+1。FW检测超过“读阈值",检测比特翻转数,决定是否"刷新",或者设一个更大的阈值。
这里的实现涉及到两个未定义的技术策略,如何确定阈值,以及如何刷新。
“读阈值”:阈值与闪存年龄有关,年龄(PE)越大,对RD的免疫力越低。故而一般采用动态阈值,PE越大,读阈值越小。
“刷新”:刷新存在阻塞和非阻塞两种策略,阻塞即专门处理刷新,缺点是时延长。非阻塞即刷新处理与其他操作并行,缺点是实现更为复杂。
问题根因:
根据第三章闪存特性的描述,随着时间的推移,电子会从绝缘氧化层中游离出来,造成可能的比特翻转(0->1),如果超过ECC的纠错能力,也就会导致数据丢失。
实际在用户层面的表现就是 长时间不使用,可能启动不了,或者启动很慢,因为在花大量时间做ECC的处理。
解决策略:
FTL需要对闪存空间进行实时扫描,跟RD的处理一样,进行数据刷新,避免丢失。
因为SLC 与 MLC和TLC相比有更好的读写寿命,SSD会拿SLC作为cache使用,把MLC或TLC配置为 SLC模式来访问,一般的flash都支持如此设置。SLC模式下的闪存块比MLC和TLC模式下更快更耐写。
SLC MLC TLC 性能和擦写次数对比如下
闪存类型 | SLC | MLC | TLC |
---|---|---|---|
每单位bit数 | 1 | 2 | 3 |
擦写次(次) | 约10W | 约5000 | 约1000 |
读时间(us) | ~25 | ~50 | ~75 |
写时间(us) | ~300 | ~600 | ~900 |
擦除时间(us) | ~1500 | ~3000 | ~4500 |
使用SLC Cache有如下优势
实际应用中,一般消费级或移动存储,会使用SLC Cache,因为可以有更好的突发性能。企业级产品因为不追求突发性能,更追求稳态速度,故而不考虑SLC Cache。而且消费级往往没有电容保护,SLC Cache可以保证lowerpage数据不丢,企业级一般有大电容保护,可以保证断电时写入。
SLC Cache的写入策略也存在两种类型
根据SLC Cache 闪存块的来源,也有三种分类。
掉电主要区分两种,正常掉电和异常掉电。
(1)正常掉电
主机会通过命令(SATA的Idle Immediately)通知SSD。
(2)异常掉电
异常掉电分为两种子场景,1、因为没有收到通知时被断电;2、收到了通知,但是没来得及处理完,被断电。
负面影响如下
1)缓存数据来不及写入到闪存,导致映射表丢失,或者缓存的用户数据丢失。
2)闪存特性问题,写MLC UpperPage断电,导致LowerPage数据破坏。
针对上述负面影响,FTL的设计目标如下
1)尽可能恢复用户数据。
2)让SSD经历异常掉电后还能正常工作。
实现方法如下
1)通过电容放电以维持一段时间的工作(不能100%保证)+ 异常掉电处理模块。
2)把RAM用Non-Volatile 但是速度很快的东西来替代(比如研发中的3D XPoint)
基本的重建方式。
用户在写入数据时会写入元数据,spare空间中的元数据包括逻辑地址(LPA,LBA),时间戳(TS)等等内容。
通过全盘扫描闪存空间,读取元数据,就可以得到La->Pa的映射关系。如果针对一笔逻辑地址,有多笔对应的物理地址(必然有其中部分物理地址是无效的),可以依赖时间戳来决定有效的物理地址。
该流程的缺点是存在重建速度的问题,如果是TB级别,扫描所有的数据页需要花费 几分钟,甚至几十分钟的时间。
快速恢复映射表的方式
定期地把SSD中RAM的数据和状态信息的数据写入到闪存中去,相当于做checkpoint快照。如果在快照C->D之间异常断电,从闪存中读取最新的快照信息即可。