大话存储II----第三章磁盘大挪移-磁盘原理与技术详解(3.10)

3.10 固态存储介质和固态硬盘

        固态存储在性能方面相对于机械键盘来说,有着无与伦比的优势,比如。没有机械寻道时间,对任何地址的访问耗费开销都相等,所以随机IO的性能很好。

3.10.1 SSD固态硬盘的硬件组成

        SSD(Solid State Drive)是一种利用Flash芯片或者DRAM芯片作为数据永久存储的硬盘。这里不可以再说磁盘了,因为Flash Drive不再使用此技术来存储数据。利用DRAM作为永久存储介质的SSD,又可称为RAM-DsK,其内部使用SDRAM内存条来存储数据,所以在外部电源断开后,需要使用电池来维持DRAM中的数据。现在比较常见的SSD为基于Flash介质的SSD,所有类型的ROM(比如EPROM,EEPROM)和Flash芯片使用一种叫做“浮动门场效应晶体管”的晶体管来保存数据。每个这样的晶体管叫做一个“Cell”,即单元。有两种类型的Cell:第一种是Single Level Cell(SLC),每个Cell可以保存1B的数据;第二种是Multi Level Cell(MLC),每个Cell可以保存2B的数据。MLC容量为SLC的两倍,但是成本却与SLC大致相同,所以相同容量的SSD,MLC芯片成本要比SLC芯片低很多。此外,MLC由于每个Cell可以存储4个状态,其复杂度比较高,所以容错率也很高。不管SLC还是MLC,都需要额外保存ECC校验信息来做数据的错误恢复。

        

        如上图,为Cell阵列的有序排列图。每个Cell串是由多个Cell串联而成,每个Cell串每次只能读写其中一个Cell,多个Cell串并联则可以并行读写多位数据。向FG中充电之后,Cell表示0,将FG放点,Cell表示1。通常一个Page中的所有位中每个位均于一个Cell串相同的位置上,那么对于一个使用2122B(含ECC)/Page的芯片来讲,就需要16896个Cell串,需要16896条串联导线。如图,将每个Cell串上所有Cell串连起来的导线称为“位线”,将多个并联的Cell串中相同的位置的Cell水平贯穿起来的导线称为“字线”。


        将多个这样的晶体管排列在一起形成阵列,就可以同时操作多个比特了。NAND就是利用大量的这种晶体管有序排列起来而形成的一种Flash芯片。如图3-35所示为一片16GB容量的Flash芯片的逻辑方框图。每4314X8=34512个Cell逻辑上形成一个Page,每个Page组成一个Block,每2048个Block组成一个区域(Plane),一整片Flash芯片由两个区域组成,一个区域存储奇数序列号的Block,另一个存储偶数序号的Block,两个Plane可以并行操作。Flash芯片的Page大小可以为2122B(含ECC)或者4313(含ECC),一般单片容量较大的Flash其Page Size也大。相应的,Block Size也会根据单片容量的不同而不同,一般有32KB、64KB、128KB、512KB(不含ECC)等规格,视不同设计而定。


        如图3-36所示,为Intel X-25M固态硬盘的拆机图,可以看到它使用了10片NAND Flash芯片,左上方为SSD控制器,左下方为RAM Buffer。最左侧为SATA物理接口。

        

            如图3-37所示为某SSD控制器芯片的方框图。其中包含多个逻辑块,外围接口部分和底层供电部分我们就不去关心了。这里讲目光集中在右半边,其中8051CPU将通过ROM中的Firmware载入IRAM中执行来实现SSD的数据IO和管理功能。Flash Controller负责向所有连接的每个NAND Flash芯片执行读写任务,每个NAND芯片用8b并行总线与Flash Controller上的每个通道连接,每时钟周期并行传递8b数据。Flash Controller与Flash芯片之间也是通过指令的方式来运作的,地址信息与数据信息都在这8位总线上传送,由于总线位宽太窄,所以一个简单的寻址操作就需要多个时钟周期才能传输完毕。芯片容量越大,那么地址也就越长,寻址时间也就越长,所以对于小块随机IO,Flash会随着容量的增加而变得越来越低效。新的Flash芯片已经有16b总线的设计了。

        对于数据写入来说,待写入的数据必须经过ECC校验之后,将数据和ECC校验信息一一并写入芯片,对于数据读取来说,数据会与其对应的ECC信息一起读出并作校验,校验正确疑惑才会通过外部接口发送出去。ECC运算器位于Flash Controller中,整个SSD会有一片很大的容量的RAM,通常是64MB或者128MB。

3.10.2 从Flash芯片抽取数据的过程

        

        如图3-38所示,当需要读出某个Page时,Flash Controller控制Flash芯片将对应这个Page的字线组电势置为0,其他所有字线组的电势则升高到一个值,而这个值又不至于使电子穿过FG绝缘层到达FG。这种动作的结果是,所有Cell串的位线被导通以便外接从位线上提取电势状态,而所有字线电压被提高的Page其感应线均被断开导致感应线不能对应Cell的电势传递到位线上,所以此时每个Cell串的位线所体现的电势值与待读出Page中所有Cell一一对应,再通过电路将每条位线上的电势值解码成1或者0从而传输到芯片外部,放置于SSD的RAM Buffer中保存,这就完成了一个Page内容的读出。SSD的IO最小单位是1个Page。

3.10.3 向Flash芯片中写入数据的过程

        对Flash芯片的写入有一个特殊的步骤。Flash芯片要求在修改一个Cell中的位的时候,在修改之前,必须先Erase即擦除掉这个Cell。这里的“Erase”有误导地意思。以机械键盘为例,机械键盘上的“数据”是永远都抹不掉的,就算扇区全部写入0,那也是说存放的全是数字0,这也是数据,而不是被抹掉。但是SSD领域却给出了这个概念,前面说过,Cell带电表示0,不带电表示1,Cell只能带负电荷,即电子,不能带正电荷。所以Cell只有两种状态,这两种状态都表示数据。

        其实,这里的Erase动作其实就是讲一大片连续的Cell一下子全部放电,这一片连续的Cell就是一个Block。即每次Erase只能一下擦除一整个Block或多个Block,将其中所有的Cell变为1状态。但是却不能单独擦除某个或者某段Page,或者单个或者多个Cell。这一点是造成后面要叙述的SSD的致命缺点的一个根本原因。Erase完成之后,Cell中全为1,此时可以向其中写入数据,如果遇到待写入某个Cell的数据位恰好为1的时候,那么对应这个Cell的电路不做任何动作,其结果仍然为1;如果遇到待写入某个Cell的数据位为0的时候,则电路将对应Cell的字线电压提高到足以让电子穿过绝缘体的高度,这个电压被加到Control Gate上,从而对Cell中的FG进行充电,充电之后,Cell的状态从1变为0,完成了写入,这个写0的动作又叫做“Programm”,即对这个Cell进行Programm。


        如图3-39所示,将待写入Cell的字线电压升高到一定的值,对Cell充电,充电成功,则在Cell的位线上会感应到一定的电势值,通过检测这些来判断电荷是否已经被充入,如果位线上并没有感应出正确的电势,则表示对应这个位线的Cell串中对应的Cell可能已经损坏。SSD会以Page为单位进行写入操作,写完一个Page,再写下一个Page。

        Flash领域里,写又称为“Programm”。由于Flash的最高表现形式——EPRROM一般是只读的,但是一旦要将其中的程序更改,则需要重新写入新程序,即Re-Programm,所以就顺便将写入Flash的过程叫做Programm了。一块崭新的SSD上所有Cell都是已经被Erase好的,也可以使用特殊的程序对整个SSD重新整盘Erase。

3.10.4 Flash芯片的通病

        Flash芯片在写入数据的时候,有诸多效率低下的地方。包括现在常用的U盘以及SSD中的Flash芯片,或者BIOS中常用的EEPROM,他们都不可避免。

        1.Flash芯片存储的通病之一:Erase Before OverWrite

        对于机械键盘来说,键盘可以直接用磁头将对应的区域磁化成任何信号,如果之前保存的数据是1,新数据还是1,则磁头对1磁化,还是1;如果新数据是0,则磁头对1磁化,结果变成了0。而Flash则不然,如果要向某个Block写入数据,则不管原来Block中是1还是0,新写入的数据是1还是0,必须先Erase整个Block为全1,然后才能向Block中写入新数据。这种额外的Erase操作大大的增加了覆盖写的开销。

        更难办的是,如果仅仅需要更改某个Block中的某个Page,那么此时就需要Erase整个Block,然后再写入这个Page。那么这个Block中除这个Page之外的其他Page中的数据在Erase之后岂不是都变成了1了吗?是的,所以,在Erase之前,需要将全部Block中的数据读入SSD的RAM Buffer,然后Erase整个Block,再将待写入的新Page中的数据在RAM中覆盖到Block中对应的Page,然后将整个更新后的Block写入Flash芯片中。可以看到,这种机制更加大了写开销,形成了大规模的写惩罚。这也是为何SSD的缓存很大的原因。

        就像CDRW光盘一样,如果你只更新其上的几KB数据,那么就先要复制出全盘700MB的数据,然后擦除所有700MB,然后再写入更改了几KB数据的700MB的数据。SSD的这种写惩罚被称为Write Amplification,我们依然使用写惩罚这个词。写惩罚有不同的惩罚倍数,比如需要修改一个512KB的Block中的一个4KB的Page。此时的写惩罚倍数=512/4KB=128。小块随机UI会产生大倍数的写惩罚。

        当SSD当向Flash中的Free Space中写入数据时,并没有写惩罚,因为Free Space自从上次被整盘Erase后没有发生任何写入动作。那么存储介质如何知道哪里是Free Space,哪里是Occupied Space呢?只有文件系统知道存储介质中哪些数据是没用的,哪些数据正在被文件系统占用,这是绝对无可置疑的,除非文件系统通过某种途径通告存储介质。SSD也不例外,一块刚被全部Erase的SSD,其上所有Block对于文件系统或者SSD本身来讲,都可以认为是Free Space。随着数据不断地写入,SSD会将曾经被写入的块的位置记录下来,记录到一份Bitmap中,每一个比特表示Flash中的一个Block。对于文件系统来说,删除文件的过程并不是向这个文件对应的存储介质空间内覆盖写入全0或者1的过程,而只是对元数据的更改,所以只会更改元数据对应的存储介质区域,因此,删除文件的过程并没有为存储介质自身制造Free Space。所以说,对于SSD来说,Free Space只会越来越少,最终导致没有Free Space,导致每个写动作都产生写惩罚,类似Copy On Write,而且Copy和Write很有可能都是一些文件系统层已经被删除的数据,做了很多无用功,写性能急剧下降。对于一块使用非常久的SSD来说,就算它被挂载到文件系统之后,其上没有任何文件,文件系统层剩余空间为100%,这种情况下,对于SSD来说,Free Space的比例很有可能却是0,也就是说只要曾经用到过多少,那么那个水位线就永远被标记在那里。

        每个Block中的Page必须按照一个方向写入,比如每个Block为128个Page,共512KB,则当这个Block被擦除之后,SSD控制器可以先向其中写入前32个Page(或者10个Page,数量不限),一段时间之后,可以向这个Block中追加写入剩余的Page(或者多次追加一定数量的Page写入)而不需要再次擦除这个Block。SSD控制器会记录每个Block中的大段连续空余空间。但是不能够跳跃的追加,比如县写入0~31这32个Page,然后写入64~127这64个Page,中间空出了32个Page没有追加,控制器时不会使用这种方式写的,Page都是连续排布的。但是一般来讲,控制器都是尽量一次写满整个Block的从而可以避免很多额外开销。

        2.Flash芯片存储的通病之二:Wear Off

        随着FG充放电次数的增多,二氧化硅绝缘层的绝缘能力将遭到损耗,最后失去绝缘性,无法保证FG中保有足够的电荷。此时,这个Call就被宣判为损坏,即Wear Off。损坏的Cell键拖累这个Cell所在的整个Page被标记为损坏,因为SSD寻址和IO的最小单位为Page。损坏的Page对应的逻辑地址将被重定向映射到其他完好的预留Page,SSD将这些重定向表保存在ROM中,每次加电均被载入RAM以供随时查询。写惩罚会大大加速Wear Off,因为写惩罚做了很多无用功,增加了不必要的擦写,这无疑使本来就很严峻的形式雪上加霜。但是对于读操作,理论上每个Cell可以承受高数量级的次数而不会损耗,所以对于读来说,无须担心。

3.10.5 SSD给自己开出的五剂良药

        面对病入膏肓的SSD写入流程设计,SSD开出了五个药方。

        1.透支体力,拆东墙补西墙

        为了避免同一个Cell被高频率擦写,SSD有这样一个办法:每次针对某个或某段逻辑LBA地址的写都写到SSD中的Free Space中,即上一次全盘Erase后从未被写过的Block/Page中,这些Free Space已经被放电,直接写入即可无需再做Copy On Write的操作了。如果再遇到针对这个或者这段LBA地址的写操作,那么SSD会再次将待写入的数据重定向到Free Space中,而将之前这个逻辑地址占用的Page标记为“Garbage”,可以回收利用。等到Block中一定比例(大部分)的Page都被标记为“Garbage”时,并且存在大批满足条件的Block,SSD会批量回收这些Block,即执行Copy On Write过程,将尚未标记为“Garbage”的Page复制到RAM Buffer,将所有Page汇集到一起,然后写入一个新的Erase的Block,再将所有待回收的Block进行Erase操作,变成了Free Space。SSD这样做就是为了将写操作平衡到所有可能的Block中,降低单位时间内每个Block的擦写次数,从而延长Cell的寿命。

        重定向写这个设计可谓是一箭双雕,既解决了Wear Off过快的问题,又解决了大倍数写惩罚问题(因为每次写都尽量重定向到Free Space,无需CoW)。但是,正如上文所述,SSD自己认为的纯Free Space只会越来越少,那么重定向写的几率就会越来越少,最后降至0,此时大倍数的写惩罚无可避免。

        由于Page的逻辑地址对应的物理地址是不断被重定向的,所以SSD内部需要维护一个地址映射表。可以看到这种设计是比较复杂的,需要SSD上的CPU具有一定的能力运行对应的算法程序。这种避免Wear Off过快的重定向算法称为Wear Leaving,即损耗平衡算法。传统机械硬盘中,逻辑上连续LBA地址同样也是大范围物理连续的,但是对于SSD,逻辑和物理的映射随着使用时间的增长而越来越乱,好在SSD不需要机械寻址,映射关系只会影响CPU计算出结果的时间而不会影响数据IO的速度,而CPU运算所耗费的时间与数据IO的时间相比可以忽略不计,所以映射关系再怎么乱也不会对IO的性能有多少影响。利用这种方式,SSD内部实现了垃圾回收清理以及新陈代谢,使得新擦除的Block源源不断地被准备好从而供应写操作。

        2.定期清理体内的垃圾,轻装上阵

        通过上面的论述,我们知道影响一块SSD寿命和写入性能的最终决定因素就是Free Space,而且是存储介质自身所看到的Free Space而不是文件系统级别的Free Space。但是SSD自身所认识的Free Space永远只会少于文件系统的Free Space,并且只会越来越趋近于0。所以,要保持SSD认识到自身更多的Free Space,就必须让文件系统来通知SSD,告诉它那些逻辑地址现在并未被任何文件或者元数据占用,可以被擦除。这种思想已经被实现了。所有SSD厂商均会提供1一个工具,叫做“Wiper”,在操作系统中运行这个工具时,此工具扫描文件系统内不用的逻辑地址,并将这些地址通知给SSD,SSD便可以将对应的Block做擦除并回收到Free Space空间内。如果用户曾经向SSD中写满了文件随后又删除了这些文件,那么请务必运行Wiper来让SSD回收这些垃圾空间,否则就会遭遇到大量的写惩罚。

        Wiper并不是实时通知SSD的,这个工具只是一次性清理垃圾,清理完后可以再次手动清理。所以,这个工具需要手动或者设置成计划任务等每隔一段时间执行一次。这种垃圾回收和上文中的那种内部垃圾回收不在一个层面上,上文中所讲的是SSD内部自身的重定向管理所产生的垃圾,而本节中所述的则是文件系统层面课感知的垃圾,被映射到SSD内部,也就变成了垃圾。

        3.扶正固本,调节新陈代谢使其持续清除体内垃圾

        定期执行垃圾清理确实可以解燃眉之急,但是也可以通过让文件系统再删除某个文件之后实时的通知SSD回收对应的空间的方式。TRIM便是这种方式的一个实现。TRIM是ATA指令标准的一个功能指令,在Linux Kernel 2.6.28中已经囊括,但是并不完善。TRIM可以使SSD起死回生,经过实际测试,开启了TRIM支持的SSD,在操作系统TRIM的支持下,可以成功地将性能提高到相对于SSD初始化使用时候的95%以上,写惩罚倍数维持在1.1倍左右。

        4.精神修炼法,提升内功

        Delay Write是一种存储系统常用的写IO优化措施。比如有先后两个针对同一地址的IO——Write1,Write2,先后被控制器收到,而在Write1尚未被写入永久存储介质之前,恰好Write2进入,此时控制器就可以直接在内存中将Write2覆盖到Write1,在写入硬盘的时候只需要写入一次即可。这种机制为“写命中”的一种情况。它减少了不必要的写盘过程,对于SSD来讲,这是很划算的。然而,如果遇到这种IO顺序比如Write1、Read2、Write3,如果此时控制器先将Write3覆盖到Write1,然后再处理Read2的话,那么Read2原本是应该读出Write1的内容的,经过Delay Write覆盖之后,却读出了Write3的内容,这就造成了数据不一致。所以,控制器再处理Delay Write时要非常小心,一定要检测两个针对同一个地址的写IO之间是否插有针对同一地址的读IO,如果有读IO,首先处理读,然后再覆盖。

        Combine Write是另一种存储系统控制器常用的写IO优化方法。对于基于机械键盘的存储系统,如果控制器在一段时间内收到了多个写IO而这些写IO的地址在逻辑上是连续的,则可以将这些小的写IO合并为针对整体连续地址段的一个大的IO,一次性写入对应的磁盘,节约了很多SCSI指令周期,提高了效率。对于SSD来说,由于SSD中的逻辑地址本来就是杂乱的映射到可能不连续的物理地址上,但是并不影响性能,所以,SSD控制器可以整合任何地址的小块写IO成一个大的写IO而不必在乎小块写IO是否连续。整合之后的大写IO被直接写向一个Free的Block中,这样做大大提高了写效率。

        5.救命稻草,有备无患

        为了防止文件系统将数据写满的极端情况,SSD干脆自己预留一部分备用空间用于重定向写。这部分空间并不通告给操作系统,只有SSD自己知道,也就是说文件系统永远也写不满SSD的全部实际物理空间,这样就有了一个永远不会占用的一份定额的Free Space用于重定向写。

        因为SSD需要对数据进行合并以及其他优化处理以适应Flash的这些劣势,所以SSD自身对接收的写IO数据使用Write Back模式,即接收到主机控制器的数据后立即返回成功,然后异步的后台处理和刷盘。所以,一旦遇到突然掉电,那么这些数据将会丢失,正因如此,SSD需要一种掉电保护机制,一般是使用一个超级电容来维持掉电之后的脏数据刷盘。

3.10.6 SSD如何处理Cell损坏

        对于机械键盘,如果出现被划伤的磁道或者损坏的扇区,也就意味着对应的磁道或者扇区中的磁粉出现问题,不能够被成功的磁化,那么磁头会感知到这个结果,因为磁化成功必定对应这电流的扰动,如果针对某块磁粉区域磁化不成功,磁头控制电路迟迟没感知到电流扰动,或者扰动没有达到一定的程度,那么就证明这片区域已经损坏。而对于Flash中的Cell,当Cell中的绝缘体被击穿一定次数之后,损坏的几率会变得很高,有时候不见得非要达到这个门限值,可能出厂就有一定量损坏的Cell,使用一段时间之后也可能时不时出现损坏。那么SSD如何判断某个Cell损坏了呢?我们知道Cell损坏之后的表现是只能表示1而无法再被充电并且屏蔽住电子了,如果某个Cell之前被充了电,为0,某时刻Cell损坏,漏电了,变为1,那么在读取这个Cell的值的时候,电路并不会感知到这个Cell之前的值其实是0,电路依然读出的是1,那么此时问题就出现了。解决这个问题的办法是使用ECC纠错码,每次读出某个Page之后,都需要ECC校验来纠错。每种Flash生成厂商都会在其Datasheet中给出一个最低要求,即使用该种颗粒起码需要配合使用何种力度的纠错码。比如8b@512b或者24b@1KB等。8b@512b意味着如果在512字节范围内出现8b错误,则是可以纠错回复的,如果超过了8b,那么就无法就错了,此时只能想上层报“不可恢复错误”。厂商给出的纠错码力度越低,就证明这种Flash颗粒的品质就越好,损坏率就越低。

猜你喜欢

转载自blog.csdn.net/qq_28814687/article/details/80312218