在做性能优化时,我们比较容易忽视的是磁盘性能的优化。现在的手机都使用 SSD 作为存储,和机械硬盘已经不是一个年代了。了解熟悉 SSD 的一些相关技术,有益于后续进行磁盘性能优化。以下内容建议好好的阅读了解,包括参考链接中的部分,相信之后对
SSD 会有一个更加立体的认识。
以下介绍一些 SSD 中涉及到的技术:
LBA 逻辑块寻址模式
LBA(Logical Block Addressing) 逻辑块寻址模式
我们知道硬盘上的一个数据区域由它所在的磁头,柱面(也就是磁道)和扇区(512字节)所唯一确定。逻辑块寻址模式把硬盘所有的物理扇区的 C/H/S
编号通过一定的规则转变成一线性的编号,在访问磁盘时,由硬盘控制器再将这种逻辑地址转换为实际硬盘的物理地址。机械硬盘的逻辑-物理地址是固定的,因为它的读/写单位相同,并且可以直接覆盖。而 SSD 就不行,因为 NAND
必须擦除才能写入(擦除是以块为单位的),所以 SSD 物理地址必须经过转换才能用在现在的文件系统上,这个转换层叫做 FTL。
由于闪存的运作特性,数据不能像在普通机械硬盘里那样被直接覆盖。当数据第一次写入 SSD 的时候,由于 SSD 内所有的颗粒都为已擦除状态,所以数据能够以页为最小单位直接写入进去(一般是4K,参考颗粒资料),SSD
上的主控制器,使用了逻辑和物理的映射表来管理着闪存(逻辑我们一般指的是操作系统 LBA,而物理指的是闪存上真正的物理地址)。
当有新的数据写入时需要替换旧的数据时,SSD 主控制器将把新的数据写入到另外的空白的闪存空间上(已擦除状态),然后更新逻辑 LBA 地址来指向到新的物理地址。而旧的地址内容就变成了无效的数据,但是要在上面再次写入的话,就需要首先擦除
掉这个无效数据(闪存运作特性,读取和写入最小单位是页,而擦除最小单位是块,一般为128 ~ 256个页)。那么问题就来了,闪存有编程的次数限制(由于闪存不能覆盖,写前必须擦,所以习惯叫编程),这样每次的编程/擦除就叫做1个 P/E (
Program/Erase cycles)周期,大家应该都知道 MLC 一般是5000 ~ 10000次,而 SLC 是10万次左右(查闪存资料)。
FTL 闪存转换层
FTL(Flash Translation Layer) 闪存转换层
我们的操作系统通常是按照扇区大小写入数据(512B)。不幸的是,闪存的读写单位是页(4KB),而且闪存的擦除操作是按照块来的(1块=128 ~ 256
页),更要命的是写入数据前必须要先擦除,也就是说不能覆盖,这就给我们现有的文件系统带来了麻烦,很明显需要更高级,更繁琐的文件系统来解决这个问题。
为了减轻操作系统的负担(不使用高级复杂的文件系统),我们可以用软件来把 NAND 的操作习惯虚拟成以独立的扇区操作(512B),这样就出现了 FTL 闪存转换层。它存在于文件系统和物理介质(NAND
FLASH)之间。有了这层转换层,操作系统就可以按照扇区操作了,不用担心碰到之前说的擦除/读/写问题。一切逻辑到物理的转换,全部由 FTL 层包了。
FTL 算法,说简单了就是一种逻辑到物理的映射,因此,当文件系统发送指令说要写入或者更新一个特定的逻辑页,FTL 事实上写入到一个不同的空闲的物理页并且更新映射表(逻辑到物理映射的关联),并把这个页上包含的旧数据
标记为无效
(更新后的文件已经写入新地址了,旧地址的文件自然就无效了)。可以说有了FTL,我们才能像平时的机械硬盘那样操作。很明显FTL的转换速度直接影响SSD的读写性能。
WL 磨损平衡
WL(Wear Leveling) 磨损平衡 - 确保闪存的每个块被写入的次数相等的一种机制
通常情况下,在 NAND
块里的数据更新频率是不同的:有些会经常更新,有些则不常更新。很明显,那些经常更新的数据所占用的块会被快速的磨损掉,而不常更新的数据占用的块磨损就小得多。为了解决这个问题,需要让每个块的编程次数尽可能保持一致:这就是需要对每个页的读取/编程操作进行监测,在最乐观的情况下,这个技术会让全盘的颗粒物理磨损程度接近并同时报废。
磨损平衡技术依赖于逻辑和物理地址的转换:也就是说,每次主机上的应用程序请求相同逻辑页地址时,内存控制器动态的映射逻辑页地址到另一个不同的物理页地址,并把这个映射的指向存放在一个特定的映射表
里。而之前过期的物理页地址就被标记为无效
并等待之后的擦除操作。这样一来,所有的物理块就能被控制在一个相同磨损范围,并同时老化
。
磨损平衡算法分静态和动态。动态的算法就是当写入新数据的时候,会自动往比较新的 NAND 块中去写,老的闪存块就放在一旁歇歇;而静态的算法就更加先进,就算没有数据写入,SSD 监测到某些 NAND 块比较老,会自动进行数据分配,让比较老的
NAND 块承担不需要写数据的储存任务。同时让较新的 NAND 块腾出空间,平日的数据读写就在比较新的 NAND
块中进行——如此一来,各个块的寿命损耗就都差不多了。动态磨损算法是基本的磨损算法:只有用户在使用中更新的文件占用的物理页地址被磨损平衡。而静态磨损算法是更高级的磨损算法:在动态磨损算法的基础上,增加了对于那些不常更新的文件占用的物理地址进行磨损平衡,这才算是真正的全盘磨损平衡。
解释的更简单点:动态 WL 就是每次都挑最年轻的 NAND 块来用,老的 NAND 块尽量不用。静态 WL 就是把长期没有修改的老数据从一个年轻 NAND 块里面搬出来,重新找个最老的 NAND 块放着,这样年轻的 NAND
块就能再度进入经常使用区。其实概念都很简单,就这么一句话,实现却非常的复杂,特别是静态。
GC 垃圾回收
GC(Garbage collection) 垃圾回收 - NAND 颗粒清洁工
把 Block X 和 Block Y 里的有效
页复制到 Block N 里,然后擦除 Block X 和 Y 作为备用的空白 NAND
。
由前面的磨损平衡机制知道,磨损平衡的执行需要有空白 NAND
来写入更新后的数据。当可以直接写入数据的备用空白 NAND
块数量低于一个阀值(厂商在主控固件里设置,一般是全盘 NAND 容量写满后),那么 SSD
主控制器就会把那些包含无效
数据的块里的所有有效
数据合并起来到新的空白 NAND
块,并删除无效
数据块来增加备用空白 NAND
块数量。这个操作就是 SSD 的垃圾回收机制。
闲置垃圾回收:很明显在进行垃圾回收时候会消耗大量的主控处理能力和带宽造成处理用户请求的性能下降,SSD 主控制器可以设置在系统闲置时候做预先
垃圾回收(提前垃圾回收操作,保证一定数量的空白 NAND
),让 SSD
在运行时候能够保持较高的性能。闲置垃圾回收的缺点是会增加额外的写入放大
,因为你刚刚垃圾回收的有效
数据,也许马上就会被更新后的数据替代而变成为无效
数据,这样就造成之前的垃圾回收做无用功了。
被动垃圾回收:每个 SSD 都支持的技术,这对 SSD 主控制器的性能提出了要求,在垃圾回收操作消耗带宽和处理能力的同时处理用户操作数据,如果没有足够强劲的主控制器性能则会造成明显的速度下降。这就是为什么很多 SSD
在全盘写满一次后会出现性能下降的原因,因为要想继续写入数据就必须要边垃圾回收边做写入。
简单点来说:GC 的本质是把包含无效
页和有效
页的块中的有效
页复制到新的只包含有效
页的块,擦除旧的无效
页占用的块,之后这个被回收
的块就能被用来写入新数据(空白 NAND)。而闲置 GC,就是提前做 GC,让``空白
NAND更多,这个行为是固件
主动去做的。Trim 能直接产生
无效页,没有 Trim 的时候,对 SSD 主控制起来说,被更新的数据,旧数据就是
无效`的。应该说 GC 是每个 SSD
的必须要有的基本功能,根本不能算是什么需要特别提出来说的功能,每次看到厂商宣称支持 GC。除非他们还在使用 U 盘时代的算法,每写一个页,都要写整个块,那样就不需要 GC了,但是会造成任何时候都一样的低下性能。SSD 的
Over-Provision 容量直接影响垃圾回收的效率。
OP 预留空间
OP(Over-Provisioning) 预留空间
预留空间一般是指用户不可操作的容量,为实际物理闪存容量减去用户可用容量。这块区域一般被用来做优化,包括磨损均衡,GC 和坏块映射。
第一层为固定的 7.37%,这个数字是如何得出的呢?我们知道机械硬盘和 SSD 的厂商容量是这样算的,1GB 是1,000,000,000 字节(10的9 次方),但是闪存的实际容量是 1GB=1,073,741,824(2的30次方),2
者相差7.37%。所以说假设 1 块 128GB 的 SSD,用户得到的容量是 128,000,000,000 字节,多出来的那个 7.37% 就被主控固件用做 OP 了。
第二层来自制造商的设置,通常为 0%,7% 和 28% 等,打个比方,对于 128G 颗粒的 SandForce 主控 SSD,市场上会有 120G 和 100G 两种型号卖,这个取决于厂商的固件设置,这个容量不包括之前的第一层
7.37%。
第三层是用户在日常使用中可以分配的预留空间,像 Fusion-IO 公司还给用户工具自己调节大小来满足不同的耐用度和性能,而用户也可以自己在分区的时候,不分到完全的 SSD 容量来达到同样的目的。
预留空间虽然让 SSD 的可用容量小了,但是带来了减少写入放大,提高耐久,提高性能的效果。
Trim
Trim是一个 ATA
指令,由操作系统发送给 SSD 主控制器,告诉主控制器哪些数据占的地址是无效
的。
要明白什么是 Trim 以及为什么它很重要,需要先知道一点文件系统的知识。
当你在电脑里删除一个文件的时候,操作系统并不会真正的去删除它。操作系统只是把这个文件地址标记为空
,可以被再次使用,这意味着这个文件占的地址已经是无效
的了。这就会带来一个问题,硬盘并不知道操作系统把这个地址标记为空
了,机械盘的话无所谓,因为可以直接在这个地址上重新覆盖写入,但是到了 SSD 上问题就来了。
NAND 需要先擦除才能再次写入数据,要得到空闲的 NAND 空间,SSD 必须复制所有的有效页到新的空闲块里,并擦除旧块(垃圾回收)。如果没有 Trim,意味着 SSD 主控制器不知道这个页是无效
的,除非再次被操作系统要求覆盖上去。
Trim 只是条指令,让操作系统告诉 SSD 主控制器这个页已经无效
了。Trim 会减少写入放大,因为主控制器不需要复制无效
的页(没 Trim 就是有效
的)到空白块里,这同时代表复制的有效
页变少了,垃圾回收的效率和 SSD
性能也提升了。
Trim 能大量减少有效
页的数量,它能大大提升垃圾回收的效率。
WA 写入放大
WA(Write amplification) 写入放大 - 闪存和固态硬盘之间相关联的一个属性。
因为闪存必须先擦除才能写入(我们也叫编程
),在执行这些操作的时候,移动(或覆盖)用户数据和元数据(Metadata)不止一次。这些多次的操作,不但增加了写入数据量,减少了 SSD
的使用寿命,而且还吃光了闪存的带宽(间接地影响了随机写入
性能)。
早在 2008 年,Intel 公司和 SiliconSystems 公司(2009 年被西部数字收购)第一次提出了写入放大并在公开稿件里用到这个术语。他们当时的说法是,写入算法不可能低于 1,但是这种说法在 2009 年被
SandForce 打破,SandForce 说他们的写入放大是 0.55。
举个最简单的例子,比如向 SSD 中写入一个 4KB
的数据。最坏的情况就是,一个块里已经没有干净空间了,但是有无效数据可以擦除。这时主控就把所有的数据读到缓存,擦除块,缓存里更新整个块的数据,再把更新后的数据写回去。这个操作带来的写入放大就是: 原本实际写入 4K
的数据,造成了整个块(1024KB)的写入操作,那就是 256 倍放大。同时带来了原本只需要简单的写入 4KB 数据的操作变成闪存读取 (
1024KB),缓存改(4KB),闪存擦(1024KB),闪存写(1024KB),延迟大大的增加,速度慢是自然了。所以说写入放大是影响 SSD 随机写入性能和寿命的关键因素。
用 100% 随机 4KB 来写入 SSD,目前的大多数 SSD 主控,在最坏的情况下写入放大可以达到 20 以上。如果是 100% 持续的从低 LBA 写到高 LBA 的话(顺序写入),写入放大可以做到 1,实际使用中写入放大会介于 2
者之间。用户还可以设置一定的预留空间来减少写入放大,假设你有个 128G 的 SSD,你只分了 64G 的区使用,那么最坏情况下的写入放大就能减少约 3 倍。
许多因素影响SSD的写入放大,下面列出了主要因素,以及它们如何影响写放大。
垃圾回收(GC) Garbage Collection
虽然增加了写入放大(被动垃圾回收不影响,闲置垃圾回收影响),但是速度有提升。这个比较特殊的算法用来整理,移动,合并,擦除闪存块来提升效率。
预留空间(OP)Over-Provisioning
减少写入放大(预留空间越大,写入放大越低),在 SSD 的闪存上划出一部分空间留给主控做优化,用户不能操作的空间。
TRIM、
开启后可以减少写入放大,一个ATA指令,由操作系统发送给 SSD 主控,告诉主控哪些数据是无效的并且可以不用做垃圾回收操作。
可用容量
减少写入放大(可用空间越大,写入放大越低),用户使用中没有用到的空间,需要有 Trim 支持,不然不会影响写入放大 (某些主控制器算法只支持对 OP 区垃圾回收,这样就不会影响)。
安全擦除 Secure Erase
减少写入放大,清除所有用户数据和相关元数据,让 SSD 重置到初始性能。
持续写入 Sequential Writes
顺序写入减少写入放大,理论上来说,持续写入的写入放大为 1,但是某些因素还是会影响这个数值。
随机写入 Random Writes (不好)
提高写入放大,随机写入会写入很多非连续的 LBA,将会大大提升写入放大。
磨损平衡(WL) Wear Leveling (不好)
直接提高写入放大,确保闪存的每个块被写入的次数相等的一种机制。
BBM 坏块管理
BBM(Bad Block Management)坏块管理
不管磨损平衡算法如何聪明,在运作中都会碰到一个头痛的问题,那就是坏块,所以一个 SSD 必须要有坏块管理机制。何谓坏块?一个 NAND
块里包含有不稳定的地址,不能保证读/写/擦的时候数据的准确性。坏块分出厂坏块和使用过程中出现的坏块,和机械硬盘的坏块表一样(P 表永久缺陷表和G 表增长缺陷表),SSD
也有坏块表。出厂坏块的话,在坏块上会有标记,所以很容易就能被识别,后期使用中出现的坏块就要靠主控制器的能力了。一般来说,越到 NAND 生命的后期(P/E 数开始接近理论最大值),坏块就会开始大量出现了。通常 NAND
出厂都包含坏块,不过厂商有个最小有效块值(NvB minimum number of valid blocks),拿 Intel 的 34nm MLC L63B 来说,1 个 Die 上 4,096 个块里至少要有 3,936
个块是好的,从这上面可以知道,虽然出厂的 NAND 可能有坏块,但是厂商保证在正常生命周期里,好块数不会低于 3936 个块。而且每个 Die 的第一个块地址(00h)在出厂时是必须保证好的(ECC 后,这个块必须有效)。NAND
出厂前都会被执行擦除操作,厂商会在出货前会把坏块标记出来(厂商会在坏块的第一个页的 SA 区 Spare Aarea上打上标记)。 这样坏块管理软件就能靠监测 SA 区标记来制作坏块表。SA 区(页中 4096 ~ 4319
的区域,用户不可访问,主要用来存放 ECC 算法,坏块信息,文件系统资料等)。由于在使用中也会产生坏块,所以 SSD 的每次编程/擦除/复制等操作后都要检查块的状态。对颗粒的 ECC 要求也要达到厂商的标准以上(主控强不强,看 ECC
能力也是一个参考)。坏块管理和平衡磨损算法都是必须的。
ECC 校验和纠错
ECC 的全称是 Error Checking and Correction,是一种用于 Nand 的差错检测和修正算法。由于 NAND Flash 的工艺不能保证 NAND 在其生命周期中保持性能的可靠,因此,在 NAND
的生产中及使用过程中会产生坏块。为了检测数据的可靠性,在应用 NAND Flash 的系统中一般都会采用一定的坏区管理机制,而管理坏区的前提是能比较可靠的进行坏区检测。如果操作时序和电路稳定性不存在问题的话,NAND Flash
出错的时候一般不会造成整个 Block 或是 Page 不能读取或是全部出错,而是整个 Page 中只有一个或几个 bit 出错,这时候 ECC 就能发挥作用了。不同颗粒有不同的基本 ECC 要求,不同主控制器支持的 ECC
能力也不同,理论上说主控越强 ECC 能力越强。
Interleaving 交叉存取技术
Interleaving NAND 交叉存取技术
交错操作可以成倍提升 NAND 的传输率,因为 NAND 颗粒封装时候可能有多 Die,多 Plane(每个 Plane 都有 4KB 寄存器),Plane 操作时候可以交叉操作(第一个 Plane
接到指令后,在操作的同时第二个指令已经发送给了第二个 Plane,以此类推),达到接近双倍甚至 4 倍的传输能力(看闪存颗粒支持度)。
参考链接:
硬盘基本知识
SSD 的磨损平衡算法
SSD 的预留空间 OP 介绍
坏块管理(Bad Block Management,BBM)
闪存结构全解:读懂固态硬盘中的“黑话”
镁光 C300 64G 测试