使用 NAND 闪存的固态硬盘,它们与机械硬盘的区别,以及它们如何影响文件删除和恢复。
介绍
我开始写这篇相当长的文章是为了自己的学习收益,当时我从 2006 年的旧款 Win 8 250GB 硬盘驱动的电脑升级到了一台带有 128GB SSD 的戴尔 Optiflex 3010。在系统盘上,我从未使用过超过 30 或 40GB 的空间,而且我既不是游戏玩家,也不是狂热的电影或音乐收藏家。至少在电脑上不是。随着我对我的新设备的不断摸索,我越来越意识到我对 SSD 中的 NAND 闪存了解甚少,不知道 SSD 是如何工作的,它们是如何读取、写入和存储数据的,以及它们使用了哪些技巧?我可以想象硬盘驱动器(HDD)在旋转的表面上写入微小的磁性记录,但 SSD 完全不同,差别巨大。
关于 SSD,还有一些长期的误解,如果能够有些思考,甚至消除其中一些,那将是很好的。也许我自己也曾怀有不少误解。不管它是如何开始的,这篇文章逐渐发展成了一篇中级技术讨论。如果你只需要知道 SSD 安静、可靠、快速,并且能够使用多年,那么就没必要再读下去了。然而,如果你认为了解如何读取 3D TLC NAND 闪存单元是有趣的,那么你别无选择,只能继续深入了解。
尽可能多的详细信息来源于企业和私人技术文章,特别是来自希捷(Seagate)和西部数据(WD),以及名字很有趣的 Flash Memory Summit(闪存峰会)。我所做的一些结论是尝试运用我能理解的逻辑和常识。NAND 闪存控制器的复杂性,它们操作方法的多样性,以及它们发展的速度,使得理解它们,更不用说跟上它们的步伐,至少可以说是困难的。我不能说我写的内容没有混淆或者完全正确,但它更像是一本指南而不是圣经。也会有一些重复的内容。而且很快它就会过时。
我感激那些我借鉴的人,也将感激那些无需任何回报(除了贡献的满足感)就指出任何错误的人。我试图解释固态硬盘(SSD)与众不同的地方,以及为什么我们根深蒂固的硬盘驱动器(HDD)思维很难理解它。
第一个误解可能是 SSD 的复数:从语法上讲,应该是 SSDs,但 SSD’s 几乎同样常见。在这里,我将坚持使用 SSD、SSDs。
软件和硬件
本文写于 2019 年及之后,几乎完全围绕以个人电脑或笔记本电脑存储设备形式出现的 NAND 闪存展开,我们将其称为固态硬盘 (SSD)。我不会通过提及无处不在的闪存驱动器或其他 NAND 闪存设备来使事情变得更加复杂。如果存在显著差异,我将尝试在发生差异时进行说明,但默认情况下指的是内置驱动器。本文不涉及手机等设备中的闪存存储。
本文的大部分细节内容是在我的电脑运行 Windows 10 家庭版系统时编写的,该系统配备了一个相当普通的内置 2.5 英寸西部数据 Green 120 GB 固态硬盘。该硬盘使用慧荣科技 SM2258XT 主控和四个 32 GB 的闪迪 05497 032G 15nm 3D TLC 闪存芯片,并内置了容量未知的 SLC 缓存。由于本文试图讨论固态硬盘作为一个整体的行为,因此使用什么主机操作系统或文件系统应该无关紧要,但在我的例子中是 Windows 和 NTFS。本文中的内容并非针对特定品牌或类型的固态硬盘,而应该是通用的。我们真正要讨论的是固态硬盘的工作原理。
我唯一使用的额外软件应用程序是 Recuvae(Piriform 出品),HexDen (HxD)。Recuva 可以列出活动文件和已删除文件及其簇分配,而 HexDen 是一款非常实用且功能强大的十六进制编辑器。Recuva 可从 www.piriform.com (现在是 https://www.ccleaner.com/ ) 免费获取,HexDen 也可从 www.mh-nexus.de 免费获取。我使用这两款软件的便携版(portable versions)。
所有的结论和观点完全是来自我个人的工作经历,以及从我自己的电脑上获取的任何数据。在接受这些话作为真理之前,最好验证或至少同意我的推理。这里的很多内容是对一个非常复杂主题的简化解释。
SSD 物理内部结构
打开固态硬盘,你会有些失望,只有一块小型印刷电路板,上面有几颗 NAND 闪存芯片和一颗主控芯片,重量轻,而且有点脆弱。至于主控内部的软件,我只能概括其基本任务。主控和内存芯片一样,通常都是从外部制造商处购买的,这似乎是司空见惯的事情。固态硬盘主控软件是专有的,非常复杂,而且受到高度保护,但所有主控都必须执行基本任务,即使我们不太清楚它是如何实现的。这里只能讨论这些任务,真正聪明的调整和技巧只能由制造商知晓。我将从一些基础知识开始。
NAND 闪存
我不打算深入探讨 NAND 闪存的内部结构,在维基百科上已经有足够多令人困惑的文章了。你真正需要知道的是,NAND(非与门)闪存利用浮动栅晶体管阵列来存储信息。浮动栅可以没有电子的充电状态,处于空(empty)
逻辑状态,或者在不同的电压阈值下充满电子,处于表示某个值的逻辑状态。NAND 闪存是非易失性的,即使 SSD 没有通电,它也能保持其状态。哦,对了,之所以称之为 flash(闪存),是因为可以同时擦除(flashed)大量的单元。
但如果你想了解更多,继续吧。这里的术语单元(cell)
和晶体管(transistor)
指的是同一物理实体,可以互换使用,我不会一直重复使用 NAND 这个词。
闪存包含多个二维晶体管阵列,并支持三种基本操作:读取、编程(写入)和擦除。除了闪存阵列外,闪存芯片还包括命令和状态寄存器、控制单元、解码器、模拟电路、缓冲器以及地址和数据总线。一个单独的芯片承载着 SSD 控制器,它向闪存芯片发送读取、编程或擦除命令。在读取操作中,控制器将物理地址传递给闪存芯片,闪存芯片定位数据并将其发送回控制器。在编程操作中,数据和物理地址都会传递给芯片。在擦除操作中,只有物理地址会传递给芯片。
闪存芯片的锁存器存储从闪存阵列传输到芯片和从芯片传输出的数据,而在读取操作期间,感应放大器用于检测比特线上的电压。控制器使用状态寄存器监控发送到芯片的命令。控制器还包括错误检查和纠正(EEC)算法,来管理芯片中的错误和可靠性问题,并确保读取或写入的数据是正确的。
阵列的每一行通过字线(Word line)连接,每一列通过比特线(Bit line)连接。在行和列的交叉点是一个浮动栅晶体管,或称为单元,逻辑数据就存储在这里。字线并行连接到晶体管,比特线串行连接。比特线的端部连接到感应放大器。
闪存阵列被划分为块,块又被划分为页。在一个块内,与每条字线相连的单元构成一个页。与位线相连的单元则表示块中的页数。常见的页面大小为 4k、8k 或 16k,128 到 256 个页面组成一个 512k 到 4mb 大小的块。页是芯片控制单元可寻址的最小数据粒度。
读取或编程操作涉及芯片控制器使用块解码器选择相关块,然后使用页解码器选择块中的页。芯片控制器还负责激活正确的模拟电路,以产生编程和擦除操作所需的电压。
虽然每行的单元格数名义上与页面大小相等,但每行的实际单元格数却高于每页的标称容量。这是因为每个页面都包含一组备用单元和数据单元。备用单元存储该页面的 ECC 位以及页面的物理地址到逻辑地址映射。控制器还可在备用区中保存有关页面的其他元数据信息。在读取操作过程中,整个页面(包括备用区中的位)都会传输到控制器。控制器中的 ECC 逻辑会检查并纠正读取的数据。在编程操作期间,控制器会将用户数据和 ECC 位传送到闪存。
系统启动时,控制器会扫描整个闪存阵列中每个页面的空闲区域,将逻辑地址到物理地址的映射加载到自己的内存中(控制器中可能有其他保存映射数据的技术)。控制器在闪存转换层(FTL)中保存逻辑地址到物理地址的映射。FTL 还执行垃圾回收,清除写入后的无效页面,并执行损耗均衡,确保所有闪存块都得到均衡使用。
由于闪存不支持原地更新,所以在内容可以被编程之前,页面需要被擦除;但不同于以页面粒度进行的编程或读取操作,擦除操作是以块粒度执行的。
2D、3D, 和 Layers(层)
在闪存架构中,一个平面闪存块,也就是一个二维的存储单元阵列,被称为 2D 闪存。如果一个或多个这样的阵列叠放在一起,那么就是 3D 闪存。3D NAND 闪存建立在一块芯片上,最多可达 32 层,是为了在平面闪存达到尺寸限制时降低成本而设计的:3D 闪存的生产成本几乎与 2D 相当,但存储容量大大增加。在 2D 和 3D 中,每个页面(即行)中的存储单元由单词线连接,而页面中的每个偏移量(即列)中的存储单元则通过位线连接(简单地说)。
3D 闪存与层叠式闪存不同,后者是将多个独立的超薄芯片堆叠在一起。这种做法成本高得令人望而却步。大多数现代消费级固态硬盘(2010 年代)都使用 3D TLC 闪存。
我能看到其中一个单元吗?
终端用户闪存的单元尺寸极小,通常为 15 纳米,范围从 43 纳米到 12 纳米不等。实际上,单元尺寸或单元直径具有误导性,因为所述尺寸并非单元任何尺寸的测量值,而是芯片上离散组件之间距离的度量。芯片上的硅层厚度约为 0.5 至 3 纳米:相比之下,氢原子的直径为 0.1 纳米,而芯片制造中使用的硅原子为 0.2 纳米。一纳米 (nm) 确实非常小,仅为一米的十亿分之一,打个比方,如果一毫米相当于一颗标准弹珠的大小(约 13 毫米),那么一米就相当于地球的大小。十亿倍的威力令人印象深刻。
SLC、MLC、TLC、QLC 及其未来发展
单级单元(SLC)有一个电子电荷阈值来指示一个位的状态,即一或零。多级单元(MLC)存储一个电压来表示两个位的状态,有三个不同的阈值分别代表 11、10、00 和 01。三级单元(TLC)存储三个位的状态,包括 111、110、100、101、001、000、010 和 011。如果有人感兴趣的话,可以推导出四级单元(QLC)使用的 15 个阈值。(我见过其他版本的阈值表示位的含义。)
不幸的是,当双级单元被开发出来时,它被称为多级单元,并被赋予了 MLC 这个缩写,这迫使每个人在想要指代多个级别的存储单元时都要费力地打出“多级单元”这个词。如果它被称为双级单元,我们就可以自由地使用 DLC、TLC 和 QLC,并用 MLC 来描述所有这些,但现在为时已晚。如果闪存只停留在 SLC 阶段,有其是/否、一/零的状态,这些解释将更容易写,希望也更容易理解。
在多级单元中,物理 NAND 页面代表两个或更多的逻辑页面。属于 MLC 的两个位分别映射到两个逻辑页面。奇数编号的页面(包括零)映射到最不重要的(右手)位,偶数编号的页面映射到最重要的(左手)位。同样,属于 TLC 的三个位分别映射到三个逻辑页面,而 QLC 映射到四个逻辑页面(TLC 和 QLC 的页面编号是未知的)。
多层单元需要支持的位数越多,其性能就越受影响。对于 SLC,控制器只需要检查是否超过了一个阈值。而 MLC 单元可以有四个值,TLC 有八个,QLC 有 16 个。为了读取单元的正确值,SSD 控制器需要使用精确的电压和多次读取来确定单元中的电荷。很明显,如果一个物理页面支持多个逻辑页面,那么该页面的读写频率将高于 SLC 页面,从而影响其使用寿命。此外,显而易见的是,TLC SSD 只需要 SLC 设备三分之一的物理单元,因此我的 120 GB TLC SSD 实际上只包含 40 GB 的 NAND 单元。
高使用率的企业级 SSD 曾经是 SLC 的天下,因为它具有更高的速度、耐用性、可靠性和读/写能力,而 MLC 和 TLC 也逐渐被企业级应用所接受。终端消费级 SSD 市场则获得了更便宜、容量更大,但速度更慢、更脆弱的多层单元。
为什么空代表一?
任何仍在关注这一点的人可能已经注意到,单层和多层单元都有一个共同点,那就是一个空的单元格(其中浮栅没有电荷)代表一。与 HDD 不同,HDD 中任何位模式都可以写入任何位置,而 SSD 页面上存在一个默认的逻辑状态 1。这是因为单元上只有一个编程功能,即跨浮栅移动电子。NAND 闪存单元只能被编程为零状态,而没有能力编程为一。对于多层单元,所有页面的默认值仍然为 1,但即使在单元格被编程并且栅极上有电子存在之后,逻辑 1 仍然可以表示。
自从斐波那契在 1202 年将带有零概念的印度-阿拉伯数字系统引入欧洲数学以来,人类的思维就将零与空联系在一起,将一与满联系在一起。空着却代表一,这让人相当困惑,而且似乎主要来自于惯例(空状态可以代表零,但需要在数据线上使用反相器)。可能是电路不那么复杂,也可能是空单元格传导电荷的能力意味着它是一。
它们都是 SLC
在讨论了这么多之后,或许有必要强调一点:无论预期用途如何,所有 NAND 闪存的物理结构都是 SLC(单层存储)。即使你能观察 TLC(三层存储)单元的内部,你也不会看到 101、011 或任何类似的数字。一个单元格中永远只可能存在一定数量的电子,无论这个数量如何解释。SSD 控制器知道应该将单元格视为 SLC、MLC 还是其他类型,并相应地对其进行编程、测量电子数量,并确定它代表的逻辑值。但即使是四层单元格也只能包含一个值,就像 SLC 单元格一样。
迷思与误解
现在我们来谈谈迷思、误解以及撰写本文的真正原因:当 SSD 页面被读取、写入和重写时会发生什么?这将如何影响已删除文件的恢复?一方面,我们有 NTFS,它专为 HDD 设计,远早于 SSD 的普及;另一方面,我们有 NAND 闪存,它有其独特的运作方式;此外,还有数十亿人多年来已经习惯了 HDD 的使用方式和预期。在这里,如果没有特别说明,我将交替使用 SSD 和 NAND 闪存,尽管这样说并不完全准确。
存储设备控制器
所有 HDD、SSD 和闪存驱动器都有一个内部控制器。用微软的话来说,控制器使得存储设备能够对主机进行“抽象化”。这种抽象是通过逻辑块寻址(LBA)实现的,其中存储设备上每个能够被寻址的簇都由主机通过一个递增的数字(LBA)来识别。存储设备控制器将该数字映射到设备上的扇区或页面。对于主机来说,这种映射是恒定的,一个簇会一直映射到同一个 LBA,直到主机更改它。在 HDD 上,这种关系是物理的、固定的:简单来说,HDD 控制器只是读取和写入主机要求的任何扇区。它不需要考虑以前那里有什么,它只是按照指令行事,将新数据写入旧数据之上。它之所以这样做,是因为它可以这样做,没有什么可以阻止新的簇直接写入旧簇的相同扇区之上。而在 SSD 上,情况就不同了。
对于 SSD,主机仍然使用 LBA 寻址系统,并不断协调 LBA 和簇号之间的关系。它知道该设备是一个 SSD,并有一些技巧来适应这一点,但这些技巧将在后面介绍。然而,SSD 控制器有许多技巧来协调为 HDD 编写的文件系统与 NAND 闪存的需求。
闪存转换层(FTL)
主机仍然使用 LBA 寻址来对 SSD 进行读写操作,因为它不知道其他方式。这些命令会被 SSD 控制器上的闪存转换层 (FTL) 拦截。FTL 维护着一个 LBA 到物理块地址 (PBA) 的映射表,并将转换后的 PBA 传递给控制器。之所以需要这个映射表,是因为与 HDD 不同,LBA 到 PBA 的关系是易失的。之所以易失,是因为 NAND 闪存的写入数据方式。
一个空的页面,所有单元都未充电,默认情况下包含全 1。然而,如果使用十六进制编辑器查看 SSD 的空扇区,它将显示为一组零。这是因为空页面没有分配给 LBA/PBA 映射表。相反,如果对一个空页面发出读取请求,则会返回一个默认的零页面。这适用于未分配的簇和属于文件的簇:SSD 不会分配一个页面并将所有单元从 1 改为 0。
浮栅晶体管
在深入了解读取和写入操作之前,这一部分可能会有所帮助,在这里,单元格和(FG)晶体管可以互换使用(一个单元格就是一个晶体管)。如果想了解更多关于浮栅金属氧化物半导体场效应晶体管(Metal-Oxide-Semiconductor Field-Effect Transistors,简称 MOSFET)的信息,可以随时查阅维基百科。
浮栅 MOS 晶体管有三个端子:栅极、漏极和源极。当一个电压被施加到栅极上时,电流就可以从源极流向漏极。施加到栅极的低电压会导致从源极到漏极的电压按比例变化。当电压升高时,这种比例响应会停止,不管怎样栅极都会关闭。
浮栅中的电荷会改变晶体管的电压阈值,即栅极关闭的点。当栅极电压高于某个值,大约 0.5 伏时,栅极总是会关闭。当电压低于这个值时,栅极的关闭由浮栅电压决定。
如果浮栅没有电荷,那么施加到栅极的低电压就会关闭栅极,并允许电流从源极流向漏极。如果浮栅带有电荷,那么需要施加更高的电压到栅极上,栅极才会关闭并且电流才会流动。浮栅中的电荷改变了为了使栅极关闭并导电所必须施加到栅极上的电压。
SSD 读取
NAND 闪存的设计并没有固有的特性来阻止对单个单元格的读取和写入。然而,为了符合 NAND 闪存设计的目标——即简单和小巧——NAND 芯片接受的标准命令被构造成页面是最小的可寻址单元。这样就省去了存储额外指令和单元格到页面映射所需的空间。
要读取单个页面及其内部的单元格,需要将该页面与块内的其他页面隔离开来。为此,未被读取的页面会被临时禁用。
同一块内的同一行(一个页面)的所有单元格/晶体管通过字线(Word Line)并联连接到晶体管的栅极。同一列(单元格偏移)的所有晶体管串联在一起,通过位线(Bit Line)连接,将一个的漏极与下一个的源极相连。在每个位线的末端是一个感应放大器。进行读取操作时,除了正在读取的页面外,所有字线上都会施加一个穿透电压。穿透电压接近或高于可能的最高阈值电压,并迫使所有未被读取页面中的晶体管关闭,不管它们是否存储了电荷。所有位线都会通入低电流。
正在读取的页面的字线会被给予一个参考电压,所有位线感应放大器进行读取。储存了足够电子数量的晶体管不会被参考电压关闭,位线电流不会通过源/漏链传递到感应放大器。没有电荷,或电荷低于阈值的晶体管会被参考电压关闭,并将位线电流传导到感应放大器。为了确定多级单元格的逻辑状态,需要进行多次不同阈值电压的读取。
(为了增加或避免更多的混淆,浮栅晶体管可以是开启或关闭状态。开启状态的栅极不导电,关闭状态的栅极则导电。所以如果栅极是开启的,就没有电流能通过;如果关闭了,就能通过。难怪我们会感到困惑。)
由此可见,要读取块中的一个页面,块中每个页面的所有晶体管都需要接收一个穿透电压或一个或多个参考电压。即使块中的其他页面部分或全部为空,这一点似乎仍然适用。这在下面的读取干扰中变得很重要。
读取存储
理解 SLC 读取背后的概念相当容易。SLC 闪存只应用一个阈值,因此只需要一个测试电压——浮栅要么关闭,要么不关闭。如果阈值电压使栅极关闭,则位线电流流向读出放大器,存储值为 1。如果没有,则为 0。
多级单元则不同,存储值位序背后的原因也变得明显。在 MLC 中,可能的用户信息位组合为 11、10、00 和 01,由三个阈值分隔。读取最高有效位 (l/h) 只需要读取一次中间阈值电压。如果栅极关闭,则最高有效位为 1,如果未关闭,则最高有效位为 0,无论最低有效位是什么。要读取最低有效位 (r/h),需要读取两次,一次读取阈值一,一次读取阈值三。如果读取阈值一使栅极关闭,则最低有效位设置为 1,不需要读取第二次。如果栅极打开,则读取阈值三。如果它关闭,则最低有效位设置为 0。如果没有,则值为 1。
TLC 单元中的位组合为 111、110、100、101、001、000、010 和 011,由七个阈值分隔,更难以理解。与 MLC 一样,最高有效位仍然只需要读取一次中间阈值。中间位需要读取两次,分别在阈值二和六,最低有效位需要读取四次,分别在阈值一、三、五和七。
所有基于最高有效位 (l/h) 的多单元页面都被视为 SLC,只需要读取一次即可确定用户信息位值。
SSD 写入
NAND 闪存最重要的方面,也是 HDD/SSD 路径上最大的分叉点,以及接下来所有内容的基础和关键因素是,数据只能写入空的 SSD 页面。这并不是什么新鲜事,也不是什么未知的事情,但它对数据安全和恢复有着最大的影响。
虽然 SSD 可以读写单个页面,但它们不能覆盖页面,因为将 0 变回 1 所需的电压会损坏相邻的单元。所有写入和重写都需要一个空白页。与 HDD 不同,HDD 会将完整的簇写入磁盘,无论之前有什么内容,写入 SSD 页面的行为是分配一个默认值为全 1 的空白页,并对需要更改为 0 的单元施加电荷。这对多级单元和 SLC 都是一样的,因为无电荷全 1 的模式要么被替换为代表另一种模式的电荷,要么保持不变。这是一个一次性的过程。
当发出写入请求时,会分配一个空页面(通常在同一个块内),然后写入数据。FTL 中的 LBA/PBA 映射会更新,以便将新页面分配给相关的 LBA。LBA 对主机来说始终保持不变:无论分配哪个页面,主机都不会知道。如果用户数据被重写或分配了一个新文件,这个过程是相同的:唯一的区别是重写的工作量会稍微多一些。旧页面将被标记为无效,主机将无法访问,但仍会占用其块内的空间,因为它无法被重用。
虽然很容易理解写入 SLC 页面的过程,但多级单元页面的情况更难想象。控制器会将新的写入累积到 SSD 缓存中,直到收集到足够多的逻辑页面来填充一个物理页面,然后才会写入物理页面。这需要对页面进行最少的写入次数。如果修改了多级页面中的一个逻辑页面,则需要分配一个新页面并重写所有逻辑页面,因为物理页面中的各个值无法更改。如果删除了一个逻辑页面,那么我推测该逻辑页面会被标记为无效,当该块成为垃圾回收的候选对象时,任何有效的逻辑页面都会在写入之前进行合并。换句话说,一个多级页面,或者至少是其中的大部分,将始终包含一整套逻辑页面。
很明显,如果 NAND 闪存以这种方式处理数据写入(事实也确实如此),那么 SSD 最终将充满有效和无效的页面,性能也会逐渐降低到爬行的程度。虽然单个 SSD 页面无法擦除,但一个块可以擦除,这种方法用于将块恢复到可写状态。为了加快这一过程,并确保始终有一组空块可用于写入,SSD 控制器会使用垃圾回收。
垃圾回收
从最简陋到容量最高的 SSD,垃圾回收功能都已启用:如果没有它,NAND 闪存将无法使用。垃圾回收是 SSD 控制器的一部分,主机并不知道它的工作。在最简单的形式中,GC 会选取一个包含有效和无效页面的块,将有效页面复制到一个新的空块中,更新 LBA 映射表,并将旧块放入无效块池中。在那里,该块及其页面将被重置为空状态,并将该块添加到可用块池中。因此,应该始终有一组可用块可用于写入活动。只要 SSD 通电,GC 就会执行其工作,无法停止。GC 例程有各种复杂的技术,所有这些技术都是专有的,而且主要只有制造商才知道。
当一个全新的 SSD 从工厂出厂时,写入操作会以渐进的线性模式逐渐填满驱动器,直到可寻址存储空间被完全写入。然而,一旦垃圾回收开始,数据写入的方式(顺序写入还是随机写入)就会影响性能。顺序写入的数据会写入整个块,当数据被替换时,整个块会被标记为无效。在垃圾回收期间,不需要将任何数据移动到另一个块。这是最快的垃圾回收方式,也就是说,没有垃圾需要回收。当数据被随机写入时,无效页面会分散在整个 SSD 中。当垃圾回收作用于包含随机写入数据的块时,必须将更多数据移动到新块,然后才能擦除该块。
垃圾回收难题
垃圾回收可以在后台进行(当主机空闲时),也可以在前台进行(当写入需要时)。虽然后台垃圾回收看起来更可取,但它也有缺点。如果主机在空闲时使用节能模式,垃圾回收要么会等待设备重新启动,从而导致用户延迟以完成垃圾回收,要么会唤醒设备并缩短电池寿命,而此时主机处于“空闲”状态。此外,垃圾回收并不知道它正在回收的数据。不可避免的是,一些数据在进行垃圾回收后不久就会被删除,从而导致另一轮垃圾回收和随之而来的额外和不必要的写入(写入放大,即实际写入与数据写入的比率)。前台垃圾回收看似与性能背道而驰,但它避免了节能问题,只在实际需要时才进行写入,并且借助快速缓存和高度发达的垃圾回收算法,不会给用户带来明显的性能损失。现代垃圾回收的趋势似乎是前台回收,或者前台和后台回收的组合。
基于前台垃圾回收,以及大多数用户活动都是随机的,那么不可避免的结论是,SSD 将在其大部分生命周期中处于满容量状态,如果我们指的是可用块,即使分配给主机的空间看起来很低。
然而,SSD 还存在另一个潜在问题,这与一个历史事件有关:文件系统的设计方式。
文件系统 —— 非眼见为实
主机文件系统的设计可以追溯到 HDD 称霸的时代,因为 SSD 那时还没有以可用且价格合理的形态出现。文件系统没有考虑到 NAND 闪存的需求。文件在不断地更新:它们被分配、移动和删除,大小也在增长和缩减。文件系统处理这些操作的方式与 NAND 闪存的工作机制不兼容。
值得强调的是,存储设备对主机操作系统是抽象的。虽然资源管理器以人类完全可以理解的形式显示了一系列文件夹和文件,但这只是一种假象。资源管理器显示的是一个完全由文件系统表中的元数据创建的逻辑结构。存储设备控制器对文件、文件夹、表或操作系统一无所知:HDD 或 SSD 看到的只是读取或写入特定扇区的命令,而它们也忠实地执行了这些命令。然而,SSD 与 HDD 相比有一个优势,它知道哪些页面保存着数据并映射到 LBA,哪些页面是空的、不保存有效数据且未映射到 LBA。相反,HDD 不需要知道这些,对 HDD 来说,所有扇区都是一样的。
文件删除
在 NTFS 文件系统中,当一个文件被删除时,主文件表 (MFT) 中的对应条目会被标记为已删除,并且集群位图也会被修改,将该文件占用的集群标记为可重用。整个删除过程只在 MFT 和集群位图中进行。这对 HDD 来说完全足够了,因为 NTFS 可以随时重用 MFT 条目和集群。
在 SSD 上,从 NTFS 的角度来看,这个过程完全相同,因为 NTFS 没有其他删除文件的方法。然而,SSD 看到的只是 HDD 看到的内容,即对几个页面的更新。HDD 和 SSD 都不知道正在更新的是 MFT 和集群位图,因为它们对这些东西一无所知。由于已删除文件的集群上没有任何活动,因此 SSD 中保存这些集群的页面仍然映射到 FTL 中的 LBA。SSD 的 FTL 无法知道这些页面不再被 NTFS 分配:对 SSD 来说,这些页面仍然有效,不会被垃圾回收清理。
由于这些“死”页面被分配给了 LBA,因此当分配或扩展文件并且主机使用该 LBA 时,它们可能会被释放。在这种情况下,该页面将被标记为无效,并使用一个新页面。然而,最终不可避免地会出现大量未被标记为垃圾回收的未使用和不需要的数据,这些数据会被 SSD 控制器毫无意义地维护,并且无法重用。为了克服这个问题,并将主机对已分配和未分配页面的视图与 SSD 的视图关联起来,从 Windows 7 开始,NTFS 获得了 TRIM 命令。
SSD 检测
尽管文件系统对存储设备进行了抽象,但为了启用文件系统针对 SSD 的一些优化,它需要知道设备是 HDD 还是 SSD。有多种方法可以做到这一点,包括查询设备的转速,对于 SSD 来说,转速应该是零(或者可能是一)。这似乎是最广泛使用和最有效的方法。
TRIM
TRIM 并非缩写,而是一条 SATA 指令,由文件系统发送至 SSD 控制器,用于指示特定页面不再包含有效数据,可以进行垃圾回收。在 Windows 系统中,只有 NTFS 卷支持 TRIM。文件删除、分区删除和磁盘格式化都会触发 TRIM。TRIM 指令需要 SSD 支持并在 NTFS 中启用才能生效。
你可以使用命令 fsutil behavior query disabledeletenotify
来检查 TRIM 是否在操作系统中启用。如果返回值为 0,则表示 TRIM 已启用。但这并不代表 SSD 支持 TRIM(甚至不能确定是否安装了 SSD),不过目前所有现代 SSD 都支持某种版本的 TRIM。
SATA 协议定义了三种不同类型的 TRIM,SSD 驱动器也实现了这三种类型:
非确定性 TRIM:在执行 TRIM 后,每次读取命令都可能返回不同的数据。
确定性 TRIM (DRAT):在执行 TRIM 后,所有读取命令都返回相同的数据(即结果是确定的),并且在写入新数据之前不会改变。
TRIM 后确定性读取零 (DZAT):在执行 TRIM 后,所有读取命令都返回零,直到该页面被写入新数据。
需要注意的是,虽然 DRAT 在读取时返回数据,但返回的数据并不是 TRIM 之前的用户数据,而是一些随机数据。
幸运的是,非确定性 TRIM 很少使用,而且 Windows 也不支持 DRAT。因此,读取已 TRIM 的页面(使用十六进制编辑器很容易做到)会调用 DZAT,并在发出 TRIM 命令后立即返回零。尽管物理页面可能没有在 TRIM 命令之后立即被清理,但 SSD 控制器知道在已 TRIM 的页面地址上没有保存有效数据。
TRIM 告诉 FTL(闪存转换层),分配给特定逻辑块地址 (LBA) 的页面将被归类为无效。当一个块不再有任何空闲页面,或者达到特定阈值时,该块就成为垃圾回收的候选对象。活动数据会被复制到一个新的空块中,而原始块会被擦除并重新可用。
TRIM 是一种异步命令,会被排队等待低优先级操作。它不需要也不发送响应。TRIM 队列的大小是有限的,在高负载情况下,一些 TRIM 命令可能会被丢弃。这种情况不会有任何提示,因此一些不需要的页面可能会逃过垃圾回收。
RETRIM
Windows 系统中的磁盘碎片整理工具(现已更名为 存储优化
)提供了一个优化 SSD 的选项。但这并不会对 SSD 进行碎片整理,而是向 NTFS 集群位图中标识的所有未分配页面发送一系列 TRIM 命令。
这种全局 TRIM(或称为 RETRIM)命令的运行粒度经过精心设计,可以确保 TRIM 队列永远不会超过其允许的大小,并且不会丢弃任何 RETRIM 命令。存储优化工具会每月自动运行一次 RETRIM。
预留空间
所有 NAND 闪存设备都使用预留空间,即额外容量,用于额外的写入操作、控制器固件、坏块替换以及 SSD 控制器使用的其他功能。这些容量并不是与用户容量物理隔离的,而仅仅是超出主机可分配空间的一部分。随着 SSD 的使用,这些额外空间中的特定页面会动态变化。
希捷公司表示,最小预留空间是二进制和十进制命名约定之间的差异。SSD 作为存储设备销售,其容量以 GB(1,000,000,000 字节)为单位。然而,NAND 闪存属于内存,以 GiB(1,073,741,824 字节)为单位,这使得最小预留空间比例略高于 7.37%。即使 SSD 在主机看来已满,它仍然拥有 7.37% 的可用空间来维持功能和执行写入操作(尽管写入性能会非常糟糕)。
除了内置的 7.37% 之外,制造商可能会进一步减少用户可用的容量,并将其作为额外的预留空间。主机也可以通过分配一个不使用驱动器全部容量的分区来创建额外的预留空间。未分配的空间将自动被控制器用作动态预留空间。
例如,我的西部数据 SSD 有四个 32 GB 的芯片,但标称容量为 120 GB,这意味着它预留了 8 GB 作为额外的预留空间。再加上 7.37% 的最小值(9.4 GB),总共 17.4 GB 的预留空间几乎占总容量的 15%。
磨损均衡
有些文件写入一次后就保持不变,而有些文件则会频繁更新。因此,一些块几乎不会进入无效块池,其擦写次数非常低,而另一些块则每隔几分钟就会进入一次池,擦写次数非常高。为了分散磨损,使所有块的擦写次数相等,并保持 SSD 在其使用寿命内的性能,就需要使用磨损均衡技术。
磨损均衡使用算法来识别擦除次数最低的块,并将内容移动到擦除次数高的块;并在分配新数据时选择擦除次数低的块。与垃圾回收一样,磨损均衡的复杂程度远远超出了我的理解范围,更不用说解释了。
读取干扰
SSD 读取操作并非完全免费,需要付出一定的代价。如上所述,读取一个页面会在该块中的所有其他单元上产生穿通电压。这种电压可能低于单元可以保持的最高阈值,但它仍然会在单元上产生微弱的编程效应,从而无意中改变其阈值电压。穿通电压会导致电隧道效应,使未读取单元的电压向更高的值移动,从而干扰单元内容。随着闪存单元尺寸的减小,晶体管氧化层变得更薄,进而增加了这种隧道效应,未读取的闪存单元只需要更少的相邻页面读取操作就会受到干扰,并进入不同的逻辑状态。保持较低阈值的单元更容易受到读取干扰的影响。
因此,每次读取都可能导致同一块中其他未读取单元的阈值电压向更高的值移动。在大量读取操作之后,这可能会导致这些单元出现读取错误。每个块都会保留一个读取计数,如果超过该计数,则会重写该块。SLC 单元的读取计数很高,大约为 100 万次,25 纳米 MLC 单元的读取计数较低,大约为 40,000 次,而 15 纳米 TLC 单元的读取计数则更低。
文件恢复
在 SSD 上,NTFS 删除文件的过程与在 HDD 上完全相同,只是多了 TRIM 命令。TRIM 命令(假设它被执行)和一些 SSD 的特性会破坏任何实际恢复已删除文件的可能性。
如上所述,TRIM 命令在 SSD 控制器中有一个对应的设置,即 DRAT 和 DZAT。(我不认为任何知名品牌的 SSD 会使用非确定性 TRIM,而且我认为 Windows 不支持 DRAT,但我没有证据。)DZAT 的实现意味着,一旦 TRIM 命令成功执行(在大多数情况下,这会在文件删除后立即执行),任何读取已 TRIM 页面的尝试都将返回零。页面上的数据在被垃圾收集器处理之前仍然存在,但这些数据无法通过任何实际方法或任何通用软件从主机访问。
垃圾回收独立于主机设备,并由 SSD 控制器决定何时调用。一旦该过程开始,就无法停止,除非关闭 SSD 的电源。一旦重新上电,垃圾收集器将恢复其职责,直到完成。
对于最终用户来说,在现代 SSD 上恢复已删除的文件几乎是不可能的,而在 Windows 下,这几乎是不可能的。从理论上对芯片进行检查很可能会显示出经过压缩和加密的数据,这些数据分布在多个块上,并且不可能将多个页面中的一个数据页与另一个数据页关联起来。有一种非常小的可能性可以恢复最近删除的文件,方法是立即关闭 SSD 的电源,并将其送到专业的 数据恢复公司。在有足够的时间和金钱的情况下,他们可能会恢复一些数据。
在删除文件(例如运行 Piriform 的 CCleaner)之后,在 SSD 上运行 Recuva。找到的已删除文件(以及可能的文件的其余部分)的标题都将为零。这是 TRIM 和 DZAT 在几秒钟内完成的工作,从而扼杀了任何恢复已删除文件的可能性。当然,TRIM 可以被禁用,但代价是性能下降,但如果要删除以后可能需要的文件,最好还是谨慎一些。
安全删除文件
安全删除文件的概念,在删除之前覆盖文件的数据,是无关紧要的,并且如果选择除零以外的任何其他模式,只会对 SSD 造成额外且毫无意义的磨损。即使使用零覆盖也会导致写入事务日志和其他文件,因此永远不应该在 SSD 上使用安全删除文件。擦除可用空间对于无意义的写入来说要糟糕得多,而且比安全删除文件更加徒劳无功。删除的文件根本就不存在了。
OCZ 论坛传说
几年前(作为对这些大段文字的一点轻松调剂),OCZ 论坛上充斥着恢复 SSD 性能的最新方法:运行 Piriform 的 CCleaner 擦除可用空间功能,并使用零进行一次覆盖。虽然性能可能已经恢复,但逻辑和常识却荡然无存。当时的理论是,用零覆盖页面等同于擦除块(这在 TRIM 出现之前)。这是无稽之谈,从一开始就应该很明显。空页面的默认状态是全 1,而不是零,而且软件怎么可能擦除 NAND 闪存?真正的原因是,当 CCleaner 用零填充页面时,SSD 控制器只是取消了页面的映射,并向主机显示默认的零页面。然后,无效页面成为垃圾收集的候选对象,这为写入提供了更大的块池,从而获得了更好的性能。这是一种在 RETRIM 发明之前的类似技术。
SSD 碎片整理
关于固态硬盘的一条准则是永远不要对其进行碎片整理。虽然将簇重新排列到相邻页面几乎没有什么好处(有一点好处)——固态硬盘在随机读取时没有明显的开销——但固态硬盘碎片整理并非完全禁止。事实上,从 Windows 8 开始,如果满足某些条件,存储优化器将对固态硬盘进行碎片整理。如果启用了系统还原,碎片级别高于 10%,并且自上次碎片整理以来至少过去了一个月,Windows 存储优化器计划维护将对固态硬盘进行碎片整理。这就是微软所说的传统碎片整理,它不是优化(RETRIM)。启用系统还原时,需要进行碎片整理以减少卷快照文件上的区段。
每月进行一次碎片整理没有什么可怕的。大多数用户不会达到 10% 的碎片标准,因此将运行简单的 RETRIM,而 Windows 10 用户无论如何都不会进行碎片整理(默认情况下,Windows 10 中禁用了系统还原)。固态硬盘寿命的减少不会被注意到。此外,尽管固态硬盘不受随机读取的影响,但文件确实会变得碎片化,这意味着 I/O 会显着增加。偶尔清理一下是有益的。
固态硬盘寿命: 许多用户担心固态硬盘的使用寿命。是的,连续的写入/擦除循环,以及额外和不可见的写入放大,确实会影响 NAND 闪存的寿命。使用固态硬盘确实会将其磨损。我的西部数据 Green 120 GB 固态硬盘,一款来自信誉良好的制造商但成本最低的三层单元 (TLC) 固态硬盘,估计寿命为 100 多万小时,写入限制为 40 TB。100 万小时是 114 年,所以我们可以忘记这一点。至于写入,以每天 1 GB 的速度(远远超过我目前的数据使用率),将需要相同的 114 年才能达到 40 TB。即使有巨大的写入开销,这款固态硬盘在可预见的未来也不会磨损。如果所有 128 GiB 的可用闪存都得到平等使用,则 40 TB 相当于每个单元 312 次写入,这是一个非常保守的数字。
结语
唯一要补充的是,NAND 闪存、固态硬盘,尤其是固态硬盘控制器,远比我在这里写的内容、我所知道的、我可能理解的以及我可能解释的更加复杂、精密和难以理解。我还应该加上“秘密”一词,因为它们的软件是专有的。虽然机械硬盘是以极低的成本实现的复杂机电工程的奇迹,但固态硬盘是以略高的成本实现的同样出色和复杂的电子和软件产品。我们应该对两者都心存感激。
你可以点击此处,返回我的主页
如果你有任何问题意见或想指出的问题,请告诉我:请发送电子邮件至 [email protected]。
© Webmaster. All rights reserved.