SSD固态硬盘,在较长时间的使用后,出现了读写性能下降的问题,我们现在要以我们的方式来看看如何解决这个问题,并告诉你面对市场上琳琅满目的SSD产品,应该如何选择呢。
在较早前我们在对INTEL X25-M进行的评测中我们发现,当时的主流级SSD或多或少都有些性能方面的问题,而X25-M并没有这样的问题。而且,后来还发现,随着时间的推移,SSD的性能会出现下降的现象,而我们测试过的基于34nm MLC NAND闪存的INTEL SSD基本没有这样的现象,它们似乎对时间并不敏感。
INTEL的X25-M系列固态硬盘开启了一个新的时代,随后三星和Indilinx推出了它们的SSD控制器,性能更高,而且没有性能上的波动,我们当然要测试这些产品。实际上,不论是普通的机械式硬盘还是基于闪存颗粒的固态硬盘,平滑的性能曲线并不足够,一个良好的固态硬盘还必须保证有较高的读写速率。
OCZ Vertex系列基于Indilinx控制器,是更大众化的选择性能的下降实际上来自于NAND闪存的工作原理。你可以最少只写入4KB的数据,但是一个数据区块是128KB(或者512KB),所以当你删除数据时它们并没有真正的被删除,除非是这个区块又重新写入新的数据。此时,会遇到一个讨厌的情况:读取-修改-写入。也就是说,当你实际只写入4KB数据的时候,控制器(也叫主控芯片)会先读入整个区块的内容(512KB),修改其中4KB的部分,然后再整个区块写入,而不是通常认为的仅仅是简单的写入4KB的数据。很明显的,写入512KB,而不是仅写入4KB的操作,大大拖慢了系统的速度。
我们在测试中模拟了这种最坏的情况,性能下降的幅度有些很轻微,有些很严重。
这就是我们今天这篇文章将要做的:对市场上基于Indilinx、Intel以及三星控制器的SSD产品进行测评,以找出它们中的最强者。不过,事情总是变化很快。
请看下面的比较图表,在运行了TRIM指令(或类似的程序等)之后,这样的差别已经大大缩小了。看来,我们需要制订新的测试方法了。
闪存基础知识:内存的速度非常快,读写均在纳秒时间内完成。不过内存的最大缺点是易失性,一旦掉电,其中的所有数据都会丢失(这个时间非常快,不超过一秒)。
另一方面,常用的磁性存储(例如硬盘),速度很慢,基于物理结构,有读写的操作。目前最快的消费级硬盘读取数据的时间是7毫秒,而速度最快的CPU读取同样的数据只需要十万分之一的时间。我们把数据存储在硬盘上的唯一原因就是因为它们便宜,而且是非易失性,即便掉电,所有的数据都还在硬盘上。
NAND闪存为我们提供了结合两者优点的选择,它们实际上是非易失性(虽然也有数据遗失的问题,不过是在十年以后),而且速度较快(数据的读写是微妙级,而不是毫秒级)。通过对一个N沟道MOSFET插入电子充电极,就可以构造出一个基本的NAND闪存单元。这样的闪存单元无须电力维持也可以很好地保持其中存储的数据信息。
一个闪存单元可以保存一比特(bit)的数据,当成千上万个单元同时集成进一片芯片中时,就可以保存成千上万个比特的数据了,再大的规模就是上GB存储量的NAND闪存颗粒了这些闪存单元有规律地按行和列排列,一组闪存单元称之为一个闪存页面。目前一个页面的大小是4KB。NAND闪存不能按比特写入,只能按页面的大小写入——也就是4KB大小。
尽管对页面进行写入很简单,不过擦除它们就要复杂些了。
受限于MOSFET的结构限制,对于NAND闪存中保存的数据,不能按单个闪存单元擦除,只能对整个“区块”进行擦除的操作。通常一个区块包含128个页面,也就是说,如果要对某个页面中的数据进行重新写入,实际操作是首先擦除掉这个页面和相邻的127个页面中的数据,然后再将新的数据写入到这128个页面中。请允许我重复一遍:改写一个页面4KB的数据实际执行的是擦除和改写512KB数据的操作。
更糟糕的是,对页面的写入操作将直接影响到它的寿命。JEDEC规定的(multi-level cell,多层单元)式闪存颗粒的极限写入次数是1万次。
为了避免闪存单元快速损耗的问题,必须在控制器中采取非常灵活的管理方法。一个设计良好的控制器必须将写入操作分散到尽可能多的区块去完成,必须避免对相同的区块执行一遍又一遍的写入操作。还有个必须要面对的问题是,有些存储的数据会频繁的更新,而另一些几天、几周、几个月甚至几年都不会更新。从你电脑的角度来说,并不需要知道控制器的这些操作细节,它只是向控制器发出写入数据的指令,对写入的数据进行分摊等复杂的操作任务必须由控制器自己独立去完成。
是不是非常难以处理?不过还好,还不是完全没有办法。
深入了解计算机的硬件技术是非常抽象的,在20年前,使用电脑需要你懂得汇编语言,后来的C、C++语言在程序员和硬件之间建立了一种抽象层,从而简化了开发过程,你可以以接近书面语言的形式更有效的控制和使用硬件。你可以编写更简单(而且更容易管理)的高水平代码,然后使用编译器优化它。
同样的原则也适用于固态硬盘。
最小的可写闪存单元是页面,实际上控制器能够直接进行写入操作的区域比单独的一个页面大得多。今天,我们在这里介绍一个逻辑页面的概念,是NAND闪存物理页面的抽象化概念。
SSD控制器最直接的写入方法就是对页面的直接写入,在这种情况下,逻辑页面的数量等于物理页面的数量。
不幸的是,这种方法有个很大的缺憾:跟踪开销。假如你的逻辑页面大小是4KB,而你的SSD容量是80GB,那么逻辑页面的数量将高达20,000,000个(实际产品是20,971,520个)。你需要一个速度很快的控制器(甚至是PC级别的处理能力),来对这么多的逻辑页面进行分类处理,这么多的逻辑页面,也需要更多更快的高速缓存/缓冲处理。
这种方法的好处却是非常高的4KB写入性能。如果你的写入操作大多数都是4KB,这种方法将产生最佳的性能。
如果控制器达不到同时控制/分类这么多逻辑页面的能力,那么就只有增加逻辑页面的大小。一个例子是将逻辑页面增加到一个“区块”(128×4KB)大小,这大大减少了控制器需要同时进行控制/分类的逻辑页面的数目。仍然以上面的80GB SSD为例,此时的逻辑页面数目大致为163,840个,如此少的数目可以大大降低控制器的设计和制造难度,普通的嵌入式处理器即可胜任这样的任务。
这种方法的好处是非常高的大文件顺序写入性能。如果你有很大的文件,那么较大的逻辑页面将是最佳的处理方式。你会发现,目前使用的数码相机,其对2MB~12MB之间大小的图像文件具有最快的写入速度,就是这个原因(它们使用了较大的逻辑页面)。
遗憾的是,连续写入性能和小文件写入性能不能同时兼顾。请记住,对文明用语C型NAND闪存的写入速率只是读取速率的1/3左右,而且在写入小文件时,这个差距会更大。如果你编写了一个8KB的文件需要写入,那么控制器实际会写入512KB的内容(以上面的例子,这是最小的可写入文件尺寸)。写入放大效应大大上升。
还记得OCZ基于Indilinx Barefoot(大脚)控制器的Vertex系列SSD?它们的逻辑页面就是512KB大小。OCZ要求Indilinx提供新的更小逻辑页面的固件,Indilinx提供了,结果就是大大改善了4KB的写入性能。
清理机制与写入放大
让我们以某个餐厅举例,假定这个餐厅一共有200张桌子,一天的客流量是1000人,那么客流量与餐桌的比例就是5:1。在每个客人走后,餐厅都需要将使用过的餐桌、碗筷等物品清理干净,以备后来的客人使用。这也就是SSD的清理机制。
请记住SSD的清理原理:可以按页面读取和写入,但必须一次性擦除整个区块。如果一个区块充满了无效的数据(例如文件已在系统级别覆盖),那么这个区块必须被擦除,然后才能写入。
所有的SSD硬盘都有这样的机制,那就是清除无效的区块以备下次使用。当SSD才投入使用时,清理机制(算法)并没有真正进入实时处理的状态,使用几天、几周、几个月后,清理算法才会实时在后台进行处理。
实际上写入的情况和此图非常相似。有数据写入时,控制器会分配一个新的区块,有效的数据和新添加的数据会写入到新的区块,旧的区块进行清理,然后将旧区块的地址信息写入“空白区块池”。控制器将已使用的区块地址从这个池中清掉,并且添加进来新的已清理区块地址,以备下次使用。
当有写入请求时,从“空闲区块池”中给这个请求分配一个新的区块,将新区块的地址信息加到“数据区块池”。包含无效数据的区块被清理,然后将地址信息添加到“空闲区块池”。
平均写延迟,甚至随机写延迟,都非常低。
虽然平均写延迟很低,但是最大写延迟却很高(仍然比机械硬盘低),这是什么原因?我们一直在说固态硬盘的清理机制(算法)和区块数据写入重组,它极少对性能产生显著的影响(因此有超低的平均写入延迟),但是个别情况下,这样的操作处理却产生了较明显的影响。
而这正是写入放大产生的原因。
只有较少几个区块可用于写入的情况(很极端的例子)。在这个例子中,清理机制(算法)只能在少数几个空白区块中进行操作,具有较多无效页面的区块被选中进行清理,当这些区块被清理,其地址信息加入到“空闲区块池”中后,原有的有效数据才会被拷贝到空闲区块中,接下来才轮到新进入的数据进行写入等操作。在最右边,你会看到接受到写入请求和将数据实际写入对应的区块中间的操作周期。当考虑到SSD进行的清理机制时,你会看到写入数据发生的延迟,这种现象被称为写入放大。
INTEL声称,它的SSD产品具有非常低的写入放大,不过1:1的写入放大因子在现实中不太可能。
写入放大因子是指SSD控制器实际写入区块的容量总和与实际文件大小的比值。这个因子为1时是最为完美的,也就是说,你想写入16KB的文件,SSD实际写入了16KB的文件,但现实往往是残酷的,这样的完美因子目前还是非常难于实现的。更高的写入放大因子意味着SSD更短的寿命和更低的性能。因此,这是个很棘手的比例因子。
数据重组与写入合并
你或许记得,SSD能够获得高性能是因为采用了多个闪存芯片并行处理的缘故。这种方式对于较大的文件很有效率,因为较大的文件更容易采用分割/并行传输的方式读取和写入在这里,我们模拟一个128KB文件的并行写入情况。它被分割成了64KB的两个部分,然后同时写入到不同的区块中:假如我们现在读取这个文件,那么也是从这些不同的区块中同时读取,非常高效。
请记住,我们前面讲过的却是小文件的随机读写性能。在PC上,小文件的读写是经常发生的,并且由于I/O操作的高延迟而成为一个难以解决的问题。下面,我们就来看看在这个超微型的SSD上,写入4KB的数据会发生什么。因为4KB是最小可写入尺寸,也就是说,这个尺寸已经不能再被分割,因此它只能通过一条通道写入。
实际上,INTEL和其他的SSD厂商已经预先猜测到这样的情况,所以在他们的产品中,小文件并不是直接写入的,而是多个小文件组合成较大的文件后,再执行分割/并行写入。
这样的处理方式并不会提高小文件随机写入的性能,因为这一切实际是被较大文件的持续写入给代替了。真正对性能产生影响的时候是在对小文件进行覆盖/重写的时候。
大文件的覆盖/重写很简单,多个区块同时被清理。
在小文件的覆盖/重写中,就不是那么简单了,在整个区块中,只有某个页面的数据需要刷新,其它页面中的数据保持不变。而且,这样的区块还不止一个。
唉,对这些分散的区块进行处理又会是个耗时的过程。如果此时再发生写入的情况,那么就会是对每个区块都进行读取/修改/写入的漫长过程。
当操作系统不支持TRIM技术的时候,对每个区块的写入操作都会有读取/修改/写入的过程,而且整个过程还有写入放大因子的不利影响。
这就是写入合并方式的缺点。
INTEL的控制器会尽力克服这样的情况,因此它的随机写入性能仍然很好。三星的控制器就没有针对这种情况处理的机制(算法)了。
现在你可以明白对整盘执行持续写入会修复碎片区块带来的不利影响了,这样的操作可以把零碎的小文件串联成一个或几个大型的“连续文件”。这同时也解释了为什么固态硬盘的性能会随着时间下降的问题。你不用担心一定要向SSD中写入连续的大文件,实际上,你对SSD操作的文件有大有小,有连续也有分散,最后你的操作都会被控制器进行合并然后再真正写入到SSD上。
写入寿命
还有个因素影响着SSD的性能:写入均衡。
每个文明用语C NAND闪存单元可写入的次数大约为1万次,超过这个次数,写入的数据就会变得不那么可靠。当然也可以使用SLC NAND闪存单元,它们可以提供10万次的写入,但价格会立马上升到2倍。
1万次的写入次数并不多,不过SSD厂商都宣称自己的产品使用寿命为1~10年。最重要的是,全部SSD厂商都宣称自己的产品比传统的机械式硬盘更可靠。
唯一的办法是赋予SSD非常聪明的算法,以及基于大量调查收集的事实:台式机用户并不总是在硬盘上进行非常大量的写入操作。
想想你现在用的硬盘吧,你多久把它们全部塞满、删除,然后重新塞满一次?INTEL估计,即便你每天向硬盘中写入20GB的数据,X25-M还可以使用至少5年的时间。实际上,20GB的写入量大大高于你日常使用中的情况。
例如:在个人电脑中,操作系统和其他的一些程序占用了不到100GB的空间(基于过去两周的统计结果),然后就是每天大约7GB写入的各种数据,让我们看看下面这些数据:如果我不再安装其他的程序,只是保持系统目前的样子,我的硬盘空间还剩余203.4GB可以用于每天7GB的写入。这意味着,大约29天后(假设SSD中的写入分配是完美的),我会把这个SSD填满。再假设我会用7天来备份这个SSD上的所有数据和程序。那么就是说,大约36天的时间,我会用掉这1万次写入寿命中的一次。简单的乘法算一下,就知道大约是36万天后这个SSD会挂掉。假设控制器对写入操作是完美的均衡操作,那么就是986年。实际上,NAND闪存中的数据最多只可以保存10年左右。
这是假定了一个具有完美写入均衡算法的SSD,但正如你猜到的那样——这是不完全可能的。
写入放大因子决定了,写入的虽然是7GB的内容,但真正写入的超过了7GB的SSD区块容量。请记住,对整个区块的写入是读取/修改/写入的过程。最坏的情况下,我只写入了4KB的文件,控制器读取了512KB的整个区块,修改其中4KB的内容,然后再写入512KB的区块,并清理掉旧的512KB区块。虽然我只使用了262,144个区块中的一个进行写入,却同时影响到其他262,143个区块的写入寿命。
当然可以对写入均衡进行深入优化以确保每个区块都得到平均的写入,不过却是以牺牲性能为代价的。
备用空间
INTEL 80GB版本的X25-M具有85,899,345,920个字节的存储空间(80×1024^3)。硬盘制造商却将80GB认为是800亿字节,因为他们使用了1GB=10亿字节的定义。因此,SSD厂商也使用相同的定义。现在,800亿字节其实等于74.5GB,这就是在你的固态硬盘上能够使用的空间。操作系统只能使用800亿个字节,实际具有85,899,345,920个字节固态硬盘实际有多少空间?80GB。操作系统让你使用多少空间?74.5GB,多出来的5.5GB哪里去了?控制器将它们作为备用空间。
INTEL的控制器是动态的,它使用剩余空间作为后备空间,直到你的文件膨胀占用更多的剩余空间。它只将非用户空间的7.5%作为自己临时的“写入均衡”(实际就是动态的备用
空间),所以可以获得更好的性能。其它的控制器也许不是动态的,但它们也可以在固态硬盘接近塞满时提供较小的性能损失。不过,即将推出的TRIM指令使得INTEL大费周章设计的优秀算法很快变得过时和无用。