简介
SSD(Solid State Drives),俗称固态硬盘,相对原来主轴旋转,并无机械部分,主要由SSD控制器,Flash存储阵列,板上DRAM(可选),以及与Host的接口(诸如SATA,SAS,PCIe等)组成。固态硬盘在接口的规范和定义、功能及使用方法上与普通硬盘的完全相同,在产品外形和尺寸上也完全与普通硬盘一致。
分类
根据存储介质,SSD可分为DRAM型的SSD和Flash的SSD。基于DRAM的SSD,采用DRAM作为存储介质,目前应用范围较窄,它仿效传统硬盘的设计、可被绝大部分操作系统的文件系统工具进行卷设置和管理,并提供工业标准的PCI和FC接口用于连接主机或者服务器。另外DRAM虽然速度更快但它属于RAM类型是不能掉电的,一旦掉电RAM内的数据就都丢失了,所以DRAM基本不用来做SSD。
基于Flash的SSD,采用Flash芯片作为存储介质,也是通常所说的SSD。这种SSD固态存储器最大的优点就是可以移动,而且数据保护不受电源控制,能适应于各种环境,但是使用年限不高。
Flash的SSD,根据电路区别,进而分为NOR(或非)型和NAND(与非)型。NOR的读速度比NAND稍快一些,NAND的写入速度比NOR快很多,NAND的4ms擦除速度远比NOR的快。
NAND又分为SLC、MLC、TLC。
SLC全称单层式储存(Single Level Cell),是指一个Block(块,Flash的基本存储单元,也可称为Cell)只有两种电荷值,高低不同的电荷值表明0或者1,因为只需要一组高低电压就可以区分出0或者1信号,所以SLC最大的驱动电压可以做到很低,传统的双电压卡或者低电压版本卡片肯定采用SLC类型的NAND Flash芯片。SLC因为结构简单,在写入数据时电压变化的区间小,所以寿命较长,传统的SLC Flash可以经受10万次的读写,因此出现坏Block的几率较小,因为存储结构非常简单,一组电压即可驱动,所以其速度表现更好,目前所有的超高速卡都采用SLC类型的Flash芯片。
MLC(多层式储存—Multi Leveled Cell)是种充分利用Block的技术,它采用较高的电压驱动,通过不同级别的电压在一个Block中记录两组位信息(00、01、11、10),这样就可以将原本SLC的记录密度理论提升一倍。不过MLC除了同制程、同晶圆面积时理论大一倍的记录空间外,存在一些先天的弊端,比如说电压区间更小,Flash就需要更多的CRC校验空间,这会大概占据Block中10%的空间,因此实际使用中同制程同晶圆面积的MLC的容量不到SLC的一倍。
因为电压变化更频繁,所以MLC技术的Flash在寿命方面远劣于SLC,官方给出的可擦写次数仅为1万次,这是MLC最要命的一个缺点。MLC技术的Flash还有一个缺点,它的读写速度先天不如SLC,一个Block存储两组位数据,自然需要更长的时间,这里面还有电压控制、CRC写入方式等因素需要考虑。
TLC 三阶存储单元(Triple-LevelCell,TLC),每个存储单元内可以存储3个Bit。由于每个单元可以存储更多的数据,TLC的成本进一步降低,但是随之而来的是写入速度和耐久度的再次降低。当然,现在市场上也有唯一一个采用TLC的SSD:三星的840,当然官方标注其P/E只有1K次。
基本原理
SSD主控通过若干通道并行操作多块Flash颗粒,类似Raid0,大大提高底层带宽。
例:假设主控与Flash颗粒之间有8个通道,每个通道挂在了一个闪存颗粒,Host与Flash之间数据传输速率为200M/s,闪存颗粒大小为8kb,Flash page的读取时间为Tr=50us,平均写入时间为Tp=800us,8kb的数据传输时间为Tx=40us。
则,底层读取最大带宽为:(8KB/(50us+40us))*8 = 711MB/s;写入最大带宽为:(8KB/(800us+40us))*8 = 76MB/s;
从上可以看出,要提高底层带宽,可以增加底层并行的颗粒数目,也可以选择速度快的Flash颗粒。
以8通道为例,来讲讲HOST怎么读写SSD。主控通过8通道连接8个Flash DIE,为方便解释,这里只画了每个DIE里的一个Block,其中每个小方块表示一个Page (假设大小为4KB)。
HOST写入4KB数据:
HOST继续写入16KB数据:
HOST继续写入,最后整个Block都写满:
SSD内部寻址方式有别于HDD,下面先介绍一下寻址方式的区别。
LBA,全称为Logical Block Address, LBA,全称为Logical Block Address,是PC数据存储装置上用来表示数据所在位置的通用机制,我们最常见到使用它的装置就是硬盘。LBA可以指某个数据区块的地址或者某个地址上所指向的数据区块。打个比方来说,LBA就等于我们平常使用的门牌地址(如:中华人民共和国广东省广州市中山四路26号)。
PBA全称为 Physics Block Address PBA全称为 Physics Block Address,相对于LBA来说,它就如GPS定位所使用的经纬度(如上面地址的经纬度为:东经:113°16′40.0621″,北纬:23°07′ 37.6129″)。
在HDD上,由于HDD的数据可以直接覆盖,所以LBA和PBA的关系是一一对应,不会变更,即LBA=PBA。但在SSD上,这种关系就变得复杂了,原因是SSD使用的存储介质NAND闪存需要先擦除才能再写入,即读写以页为单位,擦除以块(多个页组成)为单位的特性,导致LBA和 PBA的关系不再是固定不变的。因此SSD就需要一层叫做FTL(Flash translation layer)的东西来作转换,以配合现有的文件系统。
闪存的读写单位为页,而页的大小一般为4KB或8KB,但我们的操作系统读写数据是按HDD的扇区尺寸进行的(512Byte),更麻烦的是闪存擦除以块作单位,而且未擦除就无法写入,这导致操作系统现在使用的文件系统根本无法管理SSD,需要更换更先进、复杂的文件去解决这个问题, 但这样就会加重操作系统的负担。而为了不加重操作系统的负担,SSD采用软件的方式把闪存的操作虚拟成磁盘的独立扇区操作,这就是FTL。因FTL存在于文件系统和物理介质(闪存)之间,操作系统只需跟原来一样操作LBA即可,而LBA到PBA的所有转换工作,就全交由FTL负责.
回到之前的问题,当所有Channel上的Block都写满的时候,SSD主控会挑选下一个Block以同样的方式继续写入.Host通过LBA访问SSD,每个LBA代表着一个Sector(一般为512B大小),操作系统一般以4K为单位访问SSD,我们把Host访问SSD的基本单元叫用户页(Host Page)。而在SSD内部,SSD主控与Flash之间是Flash Page为基本单元访问Flash的,我们称Flash Page为物理页(Physical Page)。Host每写入一个Host Page, SSD主控会通过FTL找一个Physical Page把Host数据写入,同时记录了这样一条映射(Map),并把这个页上包含的“旧数据”标记为“无效”(更新后的数据已经写入新的PBA,旧地址的数据自然就失效了)。有了这样一个映射关系后,下次HOST需要读某个Host Page 时,SSD就知道从Flash的哪个位置把数据读取上来。
SSD内部维护了一张映射表(Map Table),Host每写入一个Host Page,就会产生一个新的映射关系,这个映射关系会加入(第一次写)或者更改(覆盖写)Map Table;当读取某个Host Page时, SSD首先查找Map Table中该Host Page对应的Physical Page,然后再访问Flash读取相应的Host数据。
一张Map Table有多大呢?这里假设我们有一个256GB的SSD,以4KB Host Page为例,那么一共有约 64M(256GB/4KB)个Host Page,也就意味着SSD需要有64M大小的Map Table。Map Table中的每个Entry存储的就是物理地址(Physical Page Address),假设其为4Byte (32 bits) ,那么整个Map Table的大小为64M*4B = 256MB。
对绝大多数SSD,我们可以看到上面都有板载DRAM,其主要作用就是用来存储这张映射表。也有例外,比如基于Sandforce主控的SSD,它并不支持板载DRAM,那么它的映射表存在哪里呢?SSD工作时,它的绝大部分映射是存储在Flash里面,还有一部分存储在片上RAM上。当Host需要读取一笔数据时,对有板载DRAM的SSD来说,只要查找DRAM当中的映射表,获取到物理地址后访问FLASH从而得到HOST数据.这期间只需要访问一次Flash;而对Sandforce的SSD来说,它首先看看该Host Page对应的映射关系是否在RAM内,如果在,那好办,直接根据映射关系读取Flash;如果该映射关系不在RAM内,那么它首先需要把映射关系从FLASH里面读取出来,然后再根据这个映射关系读取Host数据,这就意味着相比有DRAM的SSD,它需要读取两次FLASH才能把HOST数据读取出来,底层有效带宽减半。对HOST随机读来说,由于片上RAM有限,映射关系Cache命中(映射关系在片上RAM)的概率很小,所以对它来说,基本每次读都需要访问两次Flash,所以我们可以看到基于Sandforce主控的SSD随机读取性能是不太理想的。
继续回到之前的SSD写操作。当整个SSD写满后,从用户角度来看,如果想写入新的数据,则必须删除一些数据,然后腾出空间再写。用户在删除和写入数据的过程中,会导致一些Block里面的数据变无效或者变老。如下图所示(绿色小方块代表有效数据,红色小方块代表无效数据):
Block中的数据变老或者无效,是指没有任何映射关系指向它们,用户不会访问到这些FLASH空间,它们被新的映射关系所取代。比如有一个Host Page A,开始它存储在FLASH空间的X,映射关系为A->X。后来,HOST重写了该Host Page,由于FLASH不能覆盖写,SSD内部必须寻找一个没有写过的位置写入新的数据,假设为Y,这个时候新的映射关系建立:A->Y,之前的映射关系解除,位置X上的数据变老失效,我们把这些数据叫垃圾数据。
随着HOST的持续写入,FLASH存储空间慢慢变小,直到耗尽。如果不及时清除这些垃圾数据,HOST就无法写入。SSD内部都有垃圾回收机制,它的基本原理是把几个Block中的有效数据(非垃圾数据,上图中的绿色小方块表示的)集中搬到一个新的Block上面去,然后再把这几个Block擦除掉,这样就产生新的可用Block了。
上图中,Block x上面有效数据为A,B,C,Block y上面有效数据为D,E,F,G,红色方块为无效数据。垃圾回收机制就是先找一个未写过的可用Block z,然后把Block x和Block y的有效数据搬移到Block z上面去,这样Block x和Block y上面就没有任何有效数据,可以擦除变成两个可用的Block。
垃圾回收又分为后台GC和主动GC。
后台垃圾收集算法(也称为闲置垃圾收集),该控制器会使用空闲的时间来做垃圾收集,让主控在使用时一直保持高性能。例如barefoot主控. 在空闲的时候进行GC.以提高SSD性能. 在空闲的时候进行GC.以提高SSD性能。
主动GC需要有相当性能的主控制器,以保证在操作数据的同时进行GC操作 在操作数据的同时进行GC操作,这类GC适合在服务器里用到,因为个人用户可以把电脑闲置了做GC,但是服务器可不行,所以要保证性能的话必须在运行的同时做GC,这对主控制器的性能提出了很高的要求,SandForce与Marvell BJP2的主控就是这类。
一块刚买的SSD,你会发现写入速度很快,那是因为一开始总能找到可用的Block来进行写入。但是,随着你对SSD的使用,你会发现它会变慢。原因就在于SSD写满后,当你需要写入新的数据,往往需要做上述的垃圾回收:把若干个Block上面的有效数据搬移到某个Block,然后擦掉原先的Block,然后再把你的Host数据写入。这比最初单纯的找个可用的Block来写耗时多了,所以速度变慢也就可以理解了。
还是以上图为例。假设HOST要写入4KB数据 (H) ,由于当前可用Block过少,SSD开始做垃圾回收。从上图可以看出,对Block x来说,它需要把Page A,B,C的数据读出并写入到Block z,然后Block x擦除用于HOST数据写入。从Host角度,它只写了4KB数据,但从SSD内部来说,它实际写入了4个Page(Page A, B, C写入Block z,4KB数据H写入到Block x)。
写入放大
2008年,Intel公司和SiliconSystems公司(2009 年被西部数字收购)第一次提出了写入放大(Write Application)并在公开稿件里用到这个术语。
在上面例子中,Host写了4KB数据,闪存写了4个4KB数据,所以上面例子中写放大为4。对空盘来说,写放大一般为1,即Host写入多少数据,写入Flash也是多少数据量。在Sandforce控制器出来之前,写放大最小值为1。但是由于Sandforce内部具有压缩模块,它能对Host写入的数据进行实时压缩,然后再把它们写入到NAND。举个例子,HOST写入8KB数据,经压缩后,数据变为4KB,如果这个时候还没有垃圾回收,那么写放大就只有0.5。Intel之前说写放大不可能小于1,但Sandforce打破了这个说法。
预留空间
假设一个SSD,底下所有Flash容量为256GB,开放给用户使用也是256GB,那么问题就来了。想象一个场景,Host持续写满整个SSD,接着删除一些文件,写入新的文件数据,试问新的数据能写入吗?在SSD底层,如果要写入新的数据,必须要有可用的空闲Block,但由于之前256GB空间已经被HOST数据占用了,根本就没有空闲Block来写你的数据。不对,刚才不是删了一些数据吗?可以垃圾回收呀。不错,但问题来了,在上面介绍垃圾回收的时候,我们需要有Block z来写回收来的有效数据,我们这个时候连Block z都找不到,谈什么垃圾回收?所以,最后是用户写失败。
上面这个场景至少说明了一点,SSD内部需要预留空间,这部分空间HOST是看不到的。这部分预留空间,不仅仅用以做垃圾回收,事实上,SSD内部的一些系统数据,也需要预留空间来存储,比如前面说到的映射表(Map Table),比如SSD固件,以及其它的一些SSD系统管理数据。
一般从HOST角度来看,1GB= 1,000,000,000Byte,从底层Flash角度,1GB=1*1024*1024*1024Byte。256GB FLASH 为256*2^30 Byte,而一般说的256GB SSD 容量为256*10^9 Byte,这样,天然的有(256*2^30-256*^9)/(256*^9) = 7.37%的OP。
如果把256GB Flash容量的SSD配成240GB的,那么它的OP是多大呢?
(256*2^30-240*10^9)/(240*10^9) = 14.5%
除了满足基本的使用要求外,OP变大有什么坏处或者好处呢?坏处很显然,用户能使用的SSD容量变小。那么好处呢?
回到垃圾回收原理来。
再看一下这张图。回收Block x,上面有3个有效Page,需要读写3个Page完成整个Block的回收;而回收Block y时,则需要读写4个有效Page。两者相比,显然回收Block x比回收Block y快一些。说明一个简单的道理:一个Block上有效的数据越少(垃圾数据越多),则回收速度越快。
256GB FLASH配成256GB的SSD (OP = 7.37%), 意味着256*10^9的有效数据写到 256*2^30的空间,每个Block上面的平均有效数据率可以认为是256*10^9/256*2^30 = 93.1%。
如果配成240GB的SSD,则意味着240*10^9的有效数据写到256*2^30的空间,每个Block的平均有效数据率为240*10^9/256*2^30 = 87.3%。OP越大,每个Block平均有效数据率越小,因此我们可以得出的结论:OP越大,垃圾回收越快,写放大越小。这就是OP大的好处。
写放大越小,意味着写入同样多的Host数据,写入到Flash中的数据越少,也就意味着Flash损耗越小。Flash都是有一定寿命的,它是用P/E数 (Program/Erase Count)来衡量的。如果SSD集中对某几个Block进行擦写,那么这几个Block很快就寿命耗尽。比如在用户空间,有些数据是频繁需要更新的,那么这些数据所在Block就需要频繁的进行擦写,这些Block的寿命就可能很快的耗尽。相反,有些数据用户是很少更新的,比如一些只读文件,那么这些数据所在的Block擦写的次数就很少。随着用户对SSD的使用,就会形成一些Block有很高的PE数,而有些Block的PE数却很低的。这不是我们想看到的,我们希望所有Block的PE数都应该差不多,就是这些Block被均衡的使用。在SSD内部,有一种叫磨损平衡(Wear Leveling,WL)的机制来保证这点。
磨损平衡(Wear Leveling,WL)
Wear leveling也是SSD内部的FTL实现的,它通过数据迁移来达到均衡损耗的目的。Wear leveling依赖于SSD中的一部分保留空间,基本原理是在SSD中设置了两个block pool,一个是free block pool(空闲池),一个是数据池(data block pool),当需要改写某个page时(如果写入原有位置,必须先擦除整个block,然后才能写入数据),并不写入原有位置(不需要擦除的动作),而是从空闲池中取出新的block,将现有的数据和需要改写的数据合并为新的block,一起写入新的空白block,原有的block被标识为invalid状态(等待被擦除回收),新的block则进入数据池。后台任务会定时从data block中取出无效数据的block,擦除后回收到空闲池中。这样做的好处在于,一是不会反复擦写同一个block,二是写入的速度会比较快(省略了擦除的动作)。
WL有两种算法:动态WL和静态WL。所谓动态WL,就是在使用Block进行擦写操作的时候,优先挑选PE 数低的;所谓静态WL,就是把长期没有修改的老数据(如前面提到的只读文件数据)从PE数低的Block当中搬出来,然后找个PE 数高的Block进行存放,这样,之前低PE数的Block就能拿出来使用。
下面这张图诠释了无WL,动态WL和静态WL下的FLASH耐久度的区别 (假设每个Block最大PE数为10,000):(图片来自http://www.pceva.com.cn/topic/crucialssd/images/6/006.jpg)
可见,使不使用WL,以及使用何种WL算法,对SSD的寿命影响是很大的。
SSD性能指标采集
既然SSD寿命是有限的, 监控磨损率等性能指标很有必要。收集SSD的信息前,首先要了解Raid信息。市场上比较常用的服务器,诸如DELL、Lenovo等,可用MegaCli查看Raid磁盘阵列信息。
查看Raid信息:MegaCli -AdpAllInfo -aALL
查看硬盘信息:MegaCli -PDList -aALL
得到SSD的基础信息后,可使用smartctl,进一步获取SSD的详细状态参数。smartctr需要两个参数,一个是device_id,已经在MegaCLI中获取到,另一个参数是raid生成的设备,可在dmesg看到。有个这两个参数后,就可以查看SSD的运行状态了。
假设我们的device id是10,SSD在/dev/sda,那么可以用下面的命令查看具体信息:smartctl -a -d sat+megaraid,10 /dev/sda,结果如下图。
输出结果中,Media_Wearout_Indicator一项就是我们最关心的SSD的磨损率,另外还记录了一些其他状态参数,在这里不再赘述。
市面上的主流服务器中,HP是独树一帜的,MegaCli在这类品牌的机器上不好用。HP有自带的工具hpssacli,记录的信息比MegaCli要详细一点,可以使用hpssacli ctrl slot=0 show config detail命令来查看slot 0的详细信息。
输出的结果中,Bay - 1就是我们上面使用的device id。之后,同样的使用smartctl查看SSD的详细信息:
smartctl -a -d cciss, 0 /dev/sda
结果如下图,其中Media_Wearout_Indicator就是我们想要的结果。
IO调度算法
传统的IO调度算法中,大多数是针对于HDD的寻道时间进行优化,而SSD没有寻道时间,所以对IO调度的算法有所侧重。常见的IO调度算法中,最适合SSD是最简单的NOOP。NOOP实现了最最简单的FIFO队列,所有IO请求大致按照先来后到的顺序进行操作,在FIFO的基础上还做了相邻IO请求的合并。反观CFQ、AS、DeadLine等算法,虽然各有所长,但论综合能力来看,NOOP还是胜出的。
网友评论