从2005年三星作为第一个进入SSD市场的巨头,到现在短短15年,SSD已经成为非常普遍的存储介质了,相对于机械硬盘HDD,SSD在IOPS上提升了数百倍,带宽提升了数倍,如今NVMe硬盘又进一步将普通SATA SSD的性能提升了近十倍。不管是普通的SATA SSD,还是NVMe SSD,对于大多数人说,只是介质和性能上的变化,普通人甚至IT工程师会简单地认为,只要使用了SSD,存储系统访问数据的性能也会随之获得数百倍性能的提升,事实真的是这样吗?这个问题,其实很像是这样的,只要装上法拉利的发动机,车就一定快了吗?我想只有法拉利的工程师知道车身任何一度的变化,会增加多少风阻,影响百分之几秒的速度。
本文用尽可能简单的描述,为你讲清楚你想知道而不知道的SSD那些事。
你应该知道的SSD背景知识
SSD 颗粒(Cell),页(Page)和块(Block)。SSD中有两个重要的部件,一个是颗粒(Cell),另一个是控制器,关于控制器我们一会儿再说,先说说存储单元。当今的主流SSD使用的是NAND颗粒(当然有更新的SSD使用了3D NAND)来存储数据,每个颗粒可以存储1bit(SLC),2bit(MLC),3bit(TLC)甚至4bit(QLC)数据。颗粒存储的bit数越多,其密度越高,制造成本越低,但是颗粒的耐久性(或者叫寿命,擦写次数)越低。而SSD读取或写入的最小单元并不是颗粒,而是由一组颗粒组成的页(Page),典型的Page大小是4KB。SSD有一个重要特性,是颗粒一旦被写入,就不能覆盖写了,这点和基于磁介质的机械盘不同。为了能重复写,SSD需要对已经写入过的颗粒进行擦除操作(erase),而擦除的最小单元,既不是颗粒,也不是页,而是由若干个页组成的块(Block)。SSD块的典型大小是512KB或1MB,即128 Page或256 Page。SSD的其它行为以及存储系统针对SSD的优化手段,都跟这几个基本的特性有密切关系。
数据操作和垃圾回收(GC)。数据操作包括读和写,其中读延时相对稳定,写延时会发生一些变化,取决于磁盘的使用状况,正常情况下,都是几十微秒。与机械硬盘相比,SSD多了一个擦除的操作,擦除以block为单位,这点前面已经谈到了。SSD中的垃圾回收(Garbage Collection)用于回收那些已经使用过,但数据已经不再有效的那些block。SSD控制器中会设置一个可用block数量的门限,当可用block低于这个门限时,就会启动垃圾回收。
损耗均衡(Wear Leveling)和写放大(Write Amplification)。SSD block可执行有限次数的擦除操作,也称之为编程/擦写(P/E)周期,当写入非常频繁时,擦除操作发生得更频繁。一旦达到P/E最大数量,这个block就不再能写入了。对于SLC,可擦除次数通常是10万次,MLC通常是1万多次,而对于TLC块,则是几千。为了确保容量可用和写延时性能,SSD控制器需要平衡各个block的擦除次数,这是SSD控制器的核心工作之一,也称为“损耗均衡”机制。在损耗均衡期间,数据会在各个block之间移动,然后进行擦除。由于擦除的是不再有效的数据,而移动的是有效数据,因此SSD中有效数据通常会大于实际实际写入的数据,这称之为写放大WA(Write Amplification)。
SSD控制器,说了那么多,大家应该能感受到,SSD绝对不是大家想象的找个颗粒把数据写下来,需要读的时候再取出去那么简单。读写寻址、page在SSD内部的移动、block擦除、写放大的控制、损耗如何均衡,这些都是SSD控制器完成的。尤其是大家可能会困惑,数据从原来的page移动到新的地方,旧的page可能就被擦除了,上层程序怎么找得到新的地址?这就是控制器的处理逻辑,而且这里面很多逻辑甚至固化到电路里了,例如物理地址到虚拟地址的转换(上层应用就是通过虚拟地址寻址的,所以底层地址的变化完全不影响上层应用),都是电路级别的操作,延时都是微秒甚至纳秒级别。
针对SSD的存储系统优化
面向SSD这种介质与HDD存在的典型差异,存储系统也要针对SSD有针对性的优化,这些优化的效果体现在很多方面,包括性能的提升、SSD使用效率的提升、SSD寿命的延长等不同方面。以下我们列举几个常见的针对SSD存储系统的优化手段。
尽可能利用本地的SSD性能
在HDD时代,HDD的延时在毫秒级别,几乎可以抹杀掉网络延时带来的影响,所以只要保证网络协议、网络交互的优化,应用程序大可以访问远端的HDD。但是SSD的延时已经到了微秒级别,除非使用极低延时的高性能网络,否则访问远端的SSD数据的延时会明显收到影响。对于分布式存储而言,必须一方面在数据分散放置的同时,尽可能地利用本地SSD的能力,即在数据放置策略上做权衡。
在这方面,我们结合元数据放置算法和策略,对YRCloudFile分布式文件系统的元数据采用了一部分的本地化SSD访问。同时,还将推出智能缓存技术,将大量热数据缓存在指定的SSD本地设备中,进一步降低访问延时。
控制SSD容量使用量
SSD容量的使用量(即磁盘到底写多满)会影响写放大系数和GC导致的写入性能损耗。
在GC期间,需要擦除block以创建空闲block。擦除block需要保留在block内保存着有效数据的page,才能获得空闲block。创建一个空闲block可能需要压缩和挪动多个block内的page,具体数量取决于block的“满”程度。
假设SSD容量已使用A%,根据经验,为了擦除一个block,需要挪动和压缩1/1-A个block。显然,SSD的使用率越高,将需要移动更多的block以释放一个block,这将占用更多资源并导致更长的IO等待时间。例如,如果A = 50%,则仅压缩2个block以释放一个block。如果A = 80%,则大约移动5个block数据以释放一个block。如果考虑上block的page,需要操作的数据则更加惊人,假设每个块都有P个page,并且所有page都包含有效数据,则每次Garbaged Collected都需要复制PA/1-A个page。如果每个block包含128个page,当A=50%时,每个blcok都需要复制128个page,而当A = 80%时,则为512个page,当A = 95%时,则达到2432 page。如下图所示:
SD磁盘使用容量和GC移动page数量的关系
控制SSD使用容量,对于GC效率、磁盘寿命、上层应用写延时都有实际意义。
使用多线程进行小IO访问
SSD具有多个级别的内部并行处理机制,包括:channel, package, chip和plane。单个IO线程是无法充分利用所有这些并行特性的,只使用单个线程进行小IO访问,会导致整体访问延时更长。使用多个线程并发访问,则可以利用SSD内部的这些并发特性。SSD上对本机命令队列(Native Command Queuing)的支持可以有效地在多个channel之间分配读写操作,从而提高内部IO并发性。因此,上层应用或存储系统尽可能并发访问小IO,是非常有益于读写性能提升的。如果针对单个应用很难进行多线程并发,则可以考虑多个应用对数据进行并发访问,从而充分使用SSD的并发特性。
例如,我们使用一个应用程序执行10KB写IO,结果下图所示。使用一个IO线程,它可以达到115MB / s。两个线程基本上使吞吐量加倍;和4个线程再次加倍。使用8个线程可达到约500MB / s。
那么问题来了,“小”IO有多小。通常认为,充分利用SSD内部并行性的IO上限,会视为“小”的分界。例如,SSD的page大小为4KB,SSD可支持的并行度为16,则阈值为64KB。
总结
SSD已经被存储系统大量使用,通常,采用SSD的存储系统会比使用HDD的存储系统具有更好的性能,但是,在不经过针对性优化时,单纯地将SSD视为一个普通的存储设备使用,不能充分发挥出SSD,尤其是NVMe的极致性能。这是因为SSD的工作原理与普通的HDD有较大的差异,访问特性上也不同。为了充分利用SSD带来的性能优势,现代的存储系统,尤其是分布式存储系统都需要对SSD做针对性的优化。
通过这篇小文,希望让大家对SSD的工作原理,以及基本的优化手段有所了解,我们也会在以后的文章中,分享更多针对SSD编程,提升性能的手段和实践。