BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

设计SSD友好的应用

| 作者 金灵杰 关注 5 他的粉丝 发布于 2016年6月30日. 估计阅读时间: 12 分钟 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。

SSD背景知识

在应用程序针对SSD优化之前,我们首先需要对SSD的结构和特性有所了解。

  • 单元、页和块。目前主流SSD都使用NAND闪存芯片,数据存储在单元(cell)中,根据每个存储单元可以保存的位数,分为SLC(Single-Level Cell,单阶存储单元)、MLC(Multi-Level Cell,多阶存储单元)和TLC(Triple-Level Cell,三阶储存单元)。每个单元的擦除次数是有限的,单元内可存储的位越多,制造成本越低,但是可擦除次数也越少。一组单元组成了页,页是读写的最小单元。典型的页大小是4K,每次擦除后一页内的数据需要一次写入。因此对于SSD没有“覆写”操作。页被组合成块,典型的块大小有512KB、1MB等。
  • IO和垃圾收集。SSD的IO操作有三种,分别是读、写和擦除。对于读和写,最小操作单元是页,而擦除的单位是块。由于擦除的速度非常慢(通常为毫秒级),SSD控制芯片会执行垃圾回收操作,即回收使用过的块,确保后续写操作能够快速分配到可用的块。通常SSD会维护一个需要执行垃圾回收的阈值,以减少擦除过程中对应用程序实时写入的影响。
  • 损耗均衡和写入放大。SSD存储单元的擦除次数是有限的,这称为PE周期(program/erase cycles)。不同的存储单元PE周期不同,SLC最高,可以达到10万次,而TLC最低,只有几千次。如果到达了PE周期,存储单元就会永久失效。为了防止一个块经常被擦除而提前失效,SSD需要平衡每个块的擦除次数,该机制被称为“损耗均衡(wear leveling)”。通过该技术,存储数据会在不同的块之间移动,以避免对同一块的频繁擦除。由于损耗均衡策略,再加上NAND闪存芯片的擦除特性(擦除操作的最小单位是块),会导致实际SSD在擦除块之前,必须将需要保留的数据移动到新的块上,然后再进行整块擦除,这些操作都会大大增加SSD的实际写入数据,这被成为“写入放大(write amplification)”。如果应用程序针对这些特性进行了优化,可以提高SSD性能。

SSD友好应用程序的优点

相比于普通应用程序,SSD友好的应用程序有以下优点:

更高的性能

虽然直接升级到SSD已经可以大大提高应用程序的qps(queries per second,每秒查询数),如果针对SSD特性进行优化之后,还可以继续提升qps。

我们有一个应用程序,之前在使用HDD时,最高的qps为142;更换成SSD之后,即使没有对应用程序进行优化,借助于SSD的高IOPS,qps也提升到了20,000,提升了超过140倍。

当应用程序针对SSD进行了优化之后,最高性能提升到了100,000qps,又提升了超过4倍。这里的优化,主要利用了SSD内部并行处理机制(下文会提到),通过多个并行线程处理IO提升应用程序IO性能。

图1,线程和应用程序吞吐率关系

更高效的存储IO

前文提到过,SSD内部的IO最小单元是页(通常大小是4KB),因此即使是读写一个字节数据,SSD还是会操作整页数据。这也是写入放大的其中一个原因。如果应用程序非SSD友好,可能会大大增加写入放大因素。

更长的SSD寿命

SSD的寿命通常由以下因素决定:SSD大小、PE周期大小、写入放大因子和应用程序写入速率。考虑到SSD成本,如果能够优化应用程序减少写入放大因子和写入速度,能够有效延长SSD寿命。

其他层面的SSD友好设计

在进行应用程序本身的优化之前,SSD友好设计可以先从文件系统、数据库、数据存储设施层面开始考虑。

文件系统

文件系统直接和存储进行交互,文件系统的优化主要针对以下几个SSD特性:

  • 随机访问的性能比肩顺序访问;
  • 覆写需要块擦除;
  • 内部损耗均衡,这会引起写入放大。

SSD友好的文件系统有两类。一类是适配了SSD的通用文件系统,这些文件系统都通过支持SSD的TRIM指令来进行优化,包括Ext4Btrfs。另一类是专门为SSD设计的文件系统,它们自己维护了日志结构以迎合SSD的“读取-擦除-写入”流程,例如NVFSJFFS/JFFS2F2FS

数据库

传统数据库组件的设计,都充分考虑到了HDD特性。其中最受人关注的就是HDD的顺序读写性能远优于随机读写,因此数据库存储、查询优化等都会尽可能的利用该特性。

但是对于SSD来说,这些特性都可能不复存在,目前有两类专门针对SSD优化的数据库:

  • 专门针对闪存芯片设计的数据库,例如AreoSpike。它跳过文件系统直接将SSD当成快设备操作,通过写时复制尽可能避免SSD的写入放大;
  • 针对混合闪存硬盘(Hybrid flash-HDD),将其中的闪存空间作为缓存使用,以提高IO。

数据存储设施

由于HDD的延迟,读取本地HDD上的数据延迟,可能会大于网络加上内存的延迟。基于这种情况,一些公司会使用例如MemcachedRedis等内存存储集群,作为数据存储或者集中式的缓存。

但是,如果使用了SSD,情况就不同了。SSD的IO延迟可以降低到微秒级别,且相比于HDD有更高的读写带宽。相比于使用内存作为存储,SSD除了性能的提升,还可以大大降低成本和软件设计的复杂度。

SSD友好的应用程序设计

在应用程序层面,我们同样可以针对SSD特性进行优化,在提高应用程序性能的同时,提高SSD的使用寿命。

这些优化主要分为三类:数据结构、IO处理和多线程。

1.数据结构:避免就地(in-place)更新优化

由于HDD在查找数据时又寻道时间,为了避免寻道产生的延迟,应用程序常常被优化成就地更新。图1(左)展示了HDD进行就地更新和随机更新时的qps差别,可以发现对于HDD避免寻道时间,对IO的提升还是比较大的。

图2,HDD和SSD随机更新和就地更新qps

反过来看图1右侧图,对于SSD情况却截然相反。正如前文提到的,SSD的特性决定了它无法直接写入已经有数据的块,而是需要经过“读取-擦除-写入”的流程。这个流程既降低了数据写入速度,又导致了写入放大,最终导致了如图所示的qps下降。反之,对于随机写入,SSD可以寻找一个直接可写的块并写入,避免了上述流程。

2.数据结构:区分冷热数据

通常来说,应用程序在存储数据的时候,不会考虑数据访问和修改的频率。假设我们将冷热数据混合排布在同一个区块,对于SSD来说,如果要修改其中的一小块内容(小于1页),SSD仍然会读取整页的数据。这样同样会降低IO带宽和导致写入放大。

因此,出于性能考虑,如果应用程序将SSD作为数据存储,应该将数据按照访问和修改频率划分。将不同热度的数据存放在不同位置,以提高SSD读写性能。

3.数据结构:采用紧凑的数据结构

SSD的读取以页为单位,再加上操作系统通常会采用预读取操作,应用程序所采用的数据结构尽可能的紧凑,能够减少SSD的读取操作,同时也能更好地利用页缓存

同样的,由于SSD写入方式的特殊性,紧凑数据结构将关联数据放置到相邻区域,减少可能的垃圾回收的同时,还能够降低写入放大带来的问题。

4.IO处理:避免长时间大数据写入

前文介绍过,SSD内部有类似JVM的垃圾回收机制。SSD会收集内部可回收区域,并且设置一个空闲块的阈值。当空闲块数量低于阈值的时候,SSD会进行后台垃圾回收,以擦除可写区域。由于后台垃圾回收操作是异步的,因此它不会阻塞应用程序的IO操作。但如果此时写入IO频率高于后台垃圾回收的清理速度,SSD会启动前台垃圾回收。前台垃圾回收操作会阻塞的清理应用程序即将写入的块,此时应用程序IO必须等待待写入块被擦除完毕后才能执行后续的写入操作。此时应用程序IO的延迟可能会达到毫秒级。

下图是针对此特性进行的写入延迟测试,整个测试通过控制不同写入速率的数据写入,持续2小时,监测写入的延迟。

图3,高频数据写入导致的延迟

从左图我们可以看见,当写入速率达到800MB/s的时候,监测到的大于50ms延迟数量达到了61次。而右图可以看见,此速率下监测到的最大延迟达到了92ms。

5.IO处理:避免SSD使用空间过大

SSD的使用空间会影响到SSD的写入放大和垃圾回收频率。在垃圾回收过程中,块中的有效数据需要被移动到空闲的块上。假设SSD使用空间为A%,平均情况下,如果需要擦除一个块,需要压缩的块会有1/(1-A%)。在实际情况下可能会更糟糕,下图展示了随着SSD使用率上升,需要被压缩的块和页的数量:

图4,SSD使用率对块和页的压缩数量

6.线程:对于轻量IO使用多线程

SSD有不同层面的内部并行机制:通道(channel)、包装(package)、芯片(chip)和平面(plane)。单个IO线程无法充分利用这些并行机制。SSD能够通过内部的多通道机制,将多个IO线程分配到不同的通道并行进行IO操作,以提供尽可能高的IO性能。

这里的轻量IO是有多轻呢?通常的计算方式是IO数据量不超过内部的并行机制。例如,页大小为4K,并行度(通道数)为16的SSD,阈值在64KB左右。

7.线程:对于重量级IO使用较少的线程

该原则和第6条并不相矛盾,当IO的读写数据量很大时,少量IO线程(如1到2个)已经占满了SSD的总IO带宽,此时如果继续增加IO线程数,反而会降低总的IO性能。因为过量的IO线程之间,会对SSD映射表等资源产生竞争,同时也会破坏操作系统提供的预读取等优化机制。在我们的测试示例中,当写入大小为10MB的时候,单线程可以达到414MB/s的写入速率,两个线程可以提升到816MB/s的总写入速率,但是当写入线程增加到8个时,总的写入速率却降低到了500MB/s。

图5,IO大小和线程数量对吞吐率的影响

总结

应用程序使用SSD会比使用HDD有更好的IO性能。然而如果不进行应用程序优化,可能无法达到最优的性能。本文介绍的SSD友好的应用程序设计思路,可以帮助应用程序充分利用SSD的性能。


感谢陈兴璐对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT