你好,我是庄振运。
我们之前讲过,存储系统的性能很关键(参见第17讲)。我们这一讲就探讨存储方面的优化案例,是关于SSD性能的。
现在很多公司里面的高性能存储系统,一般都是基于SSD的,这主要归功于SSD价格在近几年的大幅度下降。但是,SSD也不是包治百病的灵丹妙药,也有自己的特殊性能问题。我们今天就重点讲述两点:SSD的损耗和IO访问延迟偶尔过大的问题。
这里的第二个问题可能听起来很让人吃惊:不是说SSD延迟很低吗?
一般情况下,是的。但是特殊情况下就不一定了,这个就说来话长了,它和SSD的内部原理有关。我们会一步步地探讨问题形成的原因和解决的策略。
我们的第17讲是关于存储系统的,讲过SSD的工作原理和性能。为了防止你忘记,我们就在这里快速地回顾一下其中的一个重要概念:写入放大。
什么是写入放大呢?当写入SSD的物理数据量,大于应用程序打算写入SSD的逻辑数据量时,就会造成“写入放大”。
如果是传统硬盘HDD,就不会有写入放大的问题。那么SSD为什么会有写入放大呢?这是因为SSD内部的工作原理和硬盘很不一样。
我们知道,HDD是可以直接写入覆盖的。和HDD不同,SSD里面的页面只能写入一次,要重写的话,必须先回收擦除,而且只能在“块”这个级别进行擦除。因此呢,SSD内部就需要不断地移动所存储的数据,来清空需要回收的块。也就是说,SSD内部需要进行块级别的“垃圾回收”。垃圾收集器必须有效地在SSD内部不断地回收块,回收以前使用的页面空间,然后才能在这个块上写入新数据。
因此,对SSD的写入需求,比对HDD的写入需求更高。
写入放大的缺点是什么?就是会更快地损耗SSD的生命。
每个SSD都有固定数量的擦除周期,如果在很短时间内写到SSD太多数据,就会导致SSD损耗太快,有可能过早烧坏SSD。换句话说,很高的写入速率,可能会导致SSD在到达其预期使用寿命之前就发生故障。
所以,我们要注意一个常用的指标叫:年损耗率(Burn Rate)。这个指标是怎么定义的呢?是用SSD的预期寿命推导出来的。比如一个SSD预期寿命是4年。那么每年可以损耗25%,这就是年损耗率。
前面讲的“写入放大”,其实也可以用一个相应的具体指标来衡量,就是“写入放大系数”;它代表物理写入SSD的数据与应用程序写入的逻辑数据之比。比如,如果写入放大系数是2,就表示写入每10KB的逻辑数据,SSD实际上写了20KB。为了控制SSD的年损耗率,我们需要尽量降低写入放大系数。
那么如何减少写入放大系数呢?常见的方法有两种:
这两种方法可以同时使用,我们下面分别介绍。
我们先简单说一下第一种方法。每个SSD都有一定数量的预留空间,这个空间不是SSD可用容量的一部分。这样做是有原因的。尽管我们可以使用工具来调整SSD卡上的可用容量,但是我不建议你减少预配置的可用空间,因为这将降低写入性能,并可能大大缩减SSD的使用寿命。
我们在存储数据到SSD时候,也不要存得太满,也就是不要追求太高的空间使用率。那么我们将SSD可用存储容量的使用率目标定为多少比较合适呢?一般来说,我们可以定为80%至85%,以保持较低的写入放大率。
**SSD的空闲可用空间越多,内部垃圾收集的开销就越低,就越有可能降低写入放大系数。**但是这种关系不是线性的,所以存在着收益递减的问题。
第二种方法是用Trim。我首先为你讲解一下什么是Trim。
Trim是个命令,是操作系统发给SSD控制器的特殊命令。使用Trim命令,操作系统可以通知SSD某些页面存储的数据不再有效了。比如,对于文件删除操作,操作系统会将文件的扇区标记为空闲,以容纳新数据,然后就可以将Trim命令发送到SSD。
Trim命令有什么好处呢?
SSD收到Trim命令后,SSD内部的控制器会更新其内部数据页面地图,以便在写入新数据时不去保留无效页面。并且,在垃圾回收期间不会复制无效页面,这样就实现了更有效的垃圾收集,也就减少了写操作和写入放大系数,同时获得了更高的写吞吐量,延长了驱动器的使用寿命。
Trim命令和机制虽然看起来很美好,但是实际中会产生一些问题。原因在于,不同的SSD厂商对Trim命令的处理方式,以及具体的垃圾回收机制很不一样;有的实现还不错,有的就差强人意了,因此Trim的性能在每种SSD那里会有所不同。我们后面会提到,有些SSD的厂商的某些SSD,因为对Trim的支持不太好,会造成某些情况下性能非常差。
还要注意的是,默认情况下,操作系统一般不启用Trim。因此,当文件系统删除文件时,它只是将数据块标记为“未使用”。但是SSD控制器并不知道设备上的哪些页面可用,因此无法真正释放设备上的无效空间。所以,在没有启动Trim的情况下,一旦SSD设备的可用容量填满,即使文件系统知道设备上有可用容量,SSD也会认为它自己已经存满。
那么怎么启动Trim呢?要在SSD上启用连续Trim,必须在mount这块SSD的时候使用“Discard”安装选项。如果一块SSD已经安装了,想启动Trim,那就需要卸载后重新安装,“Discard”选项才能生效。也就是说,使用remount命令是不起作用的。
所以,对于单个系统而言,最好在grub中启用mount选项,并重新启动。
Trim的使用,虽然带来了降低SSD损耗的好处,但也带来了一些坏处,特别是IO访问可能延迟加大的问题。
为什么Trim会影响应用程序性能呢?
原因和SSD内部的实际机制有关。每个SSD内部都有一个FTL(Flash Translation Layer)映射表,该表将操作系统的逻辑块地址(LBA,Logical Block Address)映射到SSD上的物理页面地址(PPA,Physical Page Address)。映射表在驱动器被写入时不断更新,以后每个读取和写入IO都要引用。
一般来说,映射表是存储在SSD驱动器的RAM中,以便快速访问;但是它的副本也存储在SSD中,目的是在电源故障时能够保留LBA到PPA的映射。随着SSD上面内容和数据的不断变化,这些变化包括新写入IO或垃圾回收,RAM中的映射表也不断更新,并且持续写入SSD中。
如果在文件系统上启用了Discard选项,那么每次删除文件时,都会生成Trim命令。因为每次Trim都会更改映射表,所以对映射表的更改也就实际地记录到SSD中。这项操作可能需要花费比较长的时间,比如几毫秒的时间才能完成,在这个更改过程中,普通的数据读取和写入I /O会阻塞,并且阻塞到所有的映射表调整都被完全处理为止。当今业界的大多数SSD都是这样工作的。
上面我们看到,由于Trim的处理会阻塞普通的数据读取和写入I /O,直到Trim完成映射表记录才返回,所以Trim的延迟对普通读写I O的延迟具有重大影响,尤其对高分位数(比如P99、P99.9)的读写IO延迟影响更大。减少Trim延迟就是减少IO延迟。所以,我们需要尽量减少Trim的等待处理时间。
另外值得你注意的是,每个SSD厂商和每款SSD,对Trim的具体处理方式都可能不同,颇有些厂商的某些SSD具有严重的问题。我们生产实践中碰到过好几种这样的SSD,比如有厂商的一种SSD在大量删除数据时有很大的延迟。这就要求我们在选购SSD时候,要特别小心,尤其是要做彻底的性能测试。
我们刚才讲了用Trim的好处和坏处。好处是可以减少SSD的损耗,延长SSD的寿命;坏处是会造成应用程序的IO读写延迟变大。
那么怎么才能尽量避免Trim带来的坏处呢?我们这里谈两种方式:一是对Discard选项本身的调优,二是使用fstrim命令。这两种方式分别对应使用Discard被启用和不被启用的两种情况。
第一种方式是在启用了Discard后,对Discard的调优。对于已经启用Discard的场景下,Trim命令默认是没有大小限制,也就是说,一次发送会尽可能多的删除命令。但是如果一次删除的数据太多,SSD可能需要很长的时间才能返回,其他读写IO就会感受到很大的延迟。
那么我们就可以微调了,这里我们就可以借助另外一个参数,discard_max_bytes对Discard进行调优。这个参数是一个操作系统内核参数,从名字也听得出,它可以指定一次Trim的最大数据量。
调整这个参数的优点,是可以根据实际可接受IO延迟的需要,来随意微调。举个例子,假如可接受IO延迟比较大,那就可以设置一个较大的discard_max_byes数值,比如2GB。使用这个参数的坏处是,当有大文件删除时,如果没有相应的重新调整参数,Trim的吞吐量会受影响。
第二种方式,是在没有启用Discard的场景下,采用fstrim来调优。fstrim也是一个命令,它可以控制Trim,来删除掉SSD上的文件系统不再使用的数据。默认情况下,fstrim将删除文件系统中所有未使用的块,但是这个命令有其他的选项,根据删除范围或大小来进行微调。
这个命令一般用于Discard没有被启用的场景下。为了达到最好的效果,都是周期性的,或者采用外部事件触发来运行这个命令,比如用Cron来每天固定时间运行;或者每当SSD存储使用率到了某个大小就运行。
下图展示了一个实际生产环境中的性能数据。
这是一个采用fstrim而降低IO延迟的例子。横轴是时间,纵轴是对SSD进行读操作的IO延迟。红色箭头是运行fstrim的时间。我们可以看到,在fstrim后,IO延迟大幅度地降低了。
采用fstrim这个方式的优点是,可以根据实际需要来决定何时运行,并且更好地微调和控制Trim的工作。
这个方式也有缺点,就是如果不够小心,运行这个命令时可能导致很长时间的SSD读写挂起阻塞,在这个阻塞的过程中,SSD完全没有响应,不能读写。我见过几次这样的生产例子,阻塞了好几分钟甚至几个小时的时间,整个SSD完全不能写入和读取数据。
SSD不断地重写会损坏其存储能力,就如同一口宝刀,不断地征战砍伐后,也会有缺口。这让我想起了唐代诗人马戴写的一首气势磅礴的《出塞词》:“金带连环束战袍,马头冲雪度临洮。卷旗夜劫单于帐,乱斫胡兵缺宝刀。”
为了延长SSD的寿命,我们可以采用Trim方式,以去除不必要的内部重写。
但是这种方式在某些特殊情况下,会增大外部IO的访问延迟。解决这一问题的方法是对Trim进行调优。我们这一讲就集中探讨了几种调优解决方案,来解决这一特殊情况下的问题。
你们公司部署SSD了吗?有没有遇到关于损耗过大的问题,以及Trim的问题和相关讨论?最后采取的解决方案是什么呢?
欢迎你在留言区分享自己的思考,与我和其他同学一起讨论,也欢迎你把文章分享给自己的朋友。