你好,我是庄振运。
前面两讲我们讨论了CPU和内存,今天我们讨论第三个重要的主题:存储系统。现在是大数据时代,这些数据终归要保存到各种存储系统里面,以供读写和分析,因此讨论存储系统的性能问题就很有必要了。
狭义上的存储往往是硬件,比如磁盘、磁带还有固态硬盘。而广义上的存储系统除了指硬件的硬盘,还包括基于网络的存储系统,比如SAN(Storage Area Network, 存储区域网络)和NAS存储(Network Attached Storage,网络接入存储)。
各种存储系统各有优缺点,尤其是性能和成本,所以对不同的需求,我们要选择最合适的存储系统。
我们首先讲存储系统最重要的三大性能指标:IOPS、访问延迟和带宽,然后讲传统硬盘HDD(Hard Disk Drive)的性能。因为传统硬盘的特性相对简单直白(毕竟业界已经用了几十年了)。这之后再讲固态硬盘的性能(固态硬盘就是SSD,也叫Flash)。相对于传统硬盘,SSD的内部工作原理很不一样,这也就导致它们的性能特性大相径庭。 最后,我们再延伸到基于网络的存储系统,并且介绍几个常用的和存储相关的工具。
一个存储系统的性能最主要的是三个:IOPS、访问延迟、吞吐率/带宽。这三个指标其实是互相关联和影响的,但是我们一般还是分开来衡量。
IOPS(Input/Output Per Second),即每秒钟能处理的读写请求数量,这是衡量存储性能的主要指标之一。每个IO的请求都有自己的特性,比如读还是写,是顺序读写还是随机读写,IO的大小是多少等。
什么是顺序读写呢?就是访问存储设备中相邻位置的数据;随机读写呢,则是访问存储设备中非相邻位置的数据。对随机读写进行性能衡量时,一般假定IO大小是4KB。
既然IO有这些特点,所以我们讨论存储系统IOPS性能的时候,经常需要更加具体的描述。比如顺序读IOPS、随机写IOPS等。
IOPS的数值会随这样的参数不同而有很大的不同,这些参数的变化,包括读取和写入的比例、其中顺序读写及随机读写的比例、读写大小、线程数量及读写队列深度等。此外,系统配置等因素也会影响IOPS的结果,例如操作系统的设置、存储设备的驱动程序特点、操作系统后台运行的作业等。
访问延迟(Access Time)和响应时间(Response Time),指的是从发起IO请求,到存储系统把IO处理完成的时间间隔,常以毫秒(ms)或者微妙(us)为单位。对这一性能指标,我们通常会考虑它的平均值和高位百分数,比如P99、P95。
吞吐率(Throughput)或者带宽(Bandwidth),衡量的是存储系统的实际数据传输速率,通常以MB/s或GB/s为单位。一般来讲,IOPS与吞吐率是紧密相关的;它们之间的关系是,吞吐率等于IOPS和IO大小的乘积。
这个也很容易理解,比如对一个硬盘的读写IO是1MB,硬盘的IOPS是100,那么硬盘总的吞吐率就是100MB/s。需要强调的是,这里IO的具体特性很重要,比如是顺序还是随机,IO大小等。
还有一点要注意,有些存储系统会因为其IO队列深度增加,而获得更好的IO性能;比如吞吐率会升高,平均访问延迟会降低。
这是为什么呢?这是因为存储系统的IO队列处理机制,可以对IO进行重新排序,从而获得好的性能。比如,它可以合并几个相邻的IO,把随机IO重新排序为顺序IO等。
我们先从你熟知的传统硬盘开始讨论。对于传统硬盘,我们应该比较熟悉它的内部是如何操作的。
简单来说,当应用程序发出硬盘IO请求后,这个请求就会进入硬盘的IO队列。如果前面有其他IO,那么这个请求可能需要排队等待。当轮到这个IO来存取数据时,磁头需要机械运动到数据存放的位置,这就需要磁头寻址到相应的磁道,并旋转到相应的扇区,然后才是数据的传输。所以,讨论硬盘IO的性能时,需要充分考虑这一点。
我们有时候需要把硬盘响应时间和硬盘访问时间分开对待。它们之间的关系是,硬盘响应时间除了包括访问时间外,还包括IO排队的延迟,如下图所示。
我们如果拿起一块硬盘仔细看看,硬盘上面往往会标注后面三个参数,分别是平均寻址时间、盘片旋转速度,以及数据传输速度,这三个参数就可以提供给我们计算上述三个步骤的时间。
平均寻址时间一般是几个毫秒。平均旋转时间可以从硬盘转动速度RPM来算出。因为每个IO请求平均下来需要转半圈,那么如果硬盘磁头每分钟转一万圈(10K RPM),转半圈就需要3毫秒。
要注意的是,硬盘上面标注的数据传输速度参数往往是最大值,实际的数据传输时间要取决于IO的大小。
对于一块普通硬盘而言,我们前面讲常用的性能数字时也提过,随机IO读写延迟就是8毫秒左右,IO带宽大约每秒100MB,而随机IOPS一般是100左右。
硬盘的技术也在发展,现代的硬盘也有很多变种。比如采用了多磁头技术,或者几块硬盘组成磁盘阵列,这样的整体IO性能也会相应地提升。
讲完了传统硬盘,我们接着看看固态硬盘——SSD。SSD的内部工作方式和HDD大相径庭,我们来了解一下。
当今的主流SSD是基于NAND的,它是将数字位存储在单元中。每个SSD单元可以存储一位(SLC,Single Level Cell,单级单元)、两位(MLC,多级单元)、三位(TLC,三级单元),甚至四位(QLC)。
SSD的特点是,对SSD单元的每次擦除,都会降低单元的寿命,因此每一个单元只能承受一定数量的擦除。所以,不同的SSD就有这几方面的考虑和平衡。单元存储的位数越多,制造成本就越少,SSD的容量也就越大。但是耐久性(擦除次数)也会降低。所以高端的SSD,比如企业级的,基本都是基于SLC的。
一个页面包括很多单元,典型的页面大小是4KB。页面也是读写的最小存储单位。我们知道,HDD可以直接对任何字节重写和覆盖;但是对SSD而言,不能直接进行上述的“覆盖”操作。SSD的一个页面里面的所有单元,一旦写入内容后就不能进行重写,必须和其它相邻页面一起,被整体擦除、重置。
在SSD内部,多个页面会组合成块。一个块的典型大小为512KB或1MB,也就是大约128或256页。块是擦除的基本单位,每次擦除,都是整个块内的所有页面都被重置。
我们总结一下,对SSD的IO操作,一共有三种类型:读取、写入和擦除。读取和写入是以页为单位的,也就是说最少也要读取写入一个页面。
IO写入的延迟,具体取决于磁盘的历史状态,因为如果SSD已经存储了许多数据,那么对页的写入,有时需要移动已有的数据,这种情况下写入延迟就比较大。但多数情况下,读写延迟都很低,一般在微秒级别,远远低于HDD。
擦除是以块为单位。擦除速度相对很慢,通常为几毫秒。所以,对同步的IO请求,发出IO的应用程序,可能会因为块的擦除而经历很大的写入延迟。为了尽量地减少这样的场景发生,一块SSD最好保持一定数量的空闲块,这样可以保证SSD的写入速度足够快。
SSD内部有垃圾回收(GC)机制,它的目的就在于此,就是不断回收不用的块,进行擦除,从而产生新的空闲块来备用。这样可以确保以后的页写入能快速分配到一个全新的页。
这是SSD相对于HDD的一个缺点,即实际写入SSD的物理数据量,有可能是应用层写入数据量的多倍。
这是因为,一方面页级别的写入需要移动已有的数据来腾空页面来写入。另一方面,GC的操作,也会移动用户数据来进行块级别的擦除。
所以,对SSD真正的写操作的数据,肯定比实际写的数据量大,这就是写入放大。因为一块SSD只能进行有限的擦除次数,也称为编程/擦除(P/E)周期,所以写入放大效用会缩短SSD的寿命。
对每一个块而言,一旦擦除造成的损耗达到最大数量,该块就会“死亡”,再也不能存储数据了。对于SLC类型的块,P/E周期的典型数目是十万次;对于MLC块,P/E周期的数目是一万;而对于TLC块,则可能是几千。为了确保整块SSD的容量、性能和可靠性,SSD内部需要对整个SSD的各块做平衡,尽量在擦除次数上保持类似。
SSD控制器具有这样一种机制,也叫“耗损平衡”,来实现这一目标。在损耗平衡操作时,数据在各个块之间移动,以实现均衡的损耗。但是这种机制也有害处,就是会对前面讲的写入放大推波助澜。
性能方面,SSD的IO性能相对于HDD来说,IOPS和访问延迟提升了上千倍,吞吐率也是提高了几十倍。但是SSD的缺点也很明显。主要有三个缺点:
好消息是,随着技术的发展,这三个缺点近几年在弱化。
如今,越来越多的应用程序采用SSD来减轻I/O性能瓶颈。许多测试和实践的结果都表明,与HDD相比,采用SSD带来了极大的应用程序性能提升。
但是,我想强调的一点是,在大多数采用SSD的部署方案中,SSD仅被视为一种“更快的HDD”,并没有真正发挥SSD的潜力。
我为什么这么说呢?因为尽管使用SSD作为存储时,应用程序可以获得更好的性能,但是这些收益,主要归因于SSD提供的更高的IOPS和带宽。
但是,SSD除了提供这些之外,它还有其它特点,比如易损耗,以及其独特的内部机制。如果应用程序的设计能充分考虑SSD的内部机制,设计出对SSD友好的应用程序,就可以更大程度地优化SSD,从而进一步提高应用程序性能,也可以延长SSD的寿命,并降低运营成本。关于这方面,我后面会有一讲专门讨论。
我们前面讨论了存储硬件,这些存储硬件可以直接安装在服务器上,构成单机系统。和单机系统和场景相对应,也有很多非单机使用的场景。
在非单机使用的场景里,这些存储硬件也被包装在各种基于网络的存储系统里。这样的存储系统也有很多种,比如DAS、NAS和SAN。
DAS(Directed Attached Storage)是直连式存储。这是以服务器为中心的存储系统,存储设备直接通过I/O总线连在服务器主机上。这种存储一般运行SATA或者SAS等协议,可以让网络的客户端直接使用。
NAS(Network Attached Storage)是网络接入存储。在NAS存储结构中,存储系统不再通过I/O总线只属于某个特定的服务器,而是通过网络接口直接与网络相连。NAS提供的是文件服务器的功能(比如NFS和CIFS),供客户通过网络访问。
SAN(Storage Area Network)是存储区域网络。SAN是一种以网络为中心的存储系统,通常有高性能专用网络(比如光纤)来支持,运行iSCSI等协议。
最后,我们看看常用的存储系统性能监测和测试工具。存储系统的测试和监控命令工具非常多,下面简单介绍几个。
Linux系统上可以采用fio工具进行各种组合的IO测试。这些组合包括读写比例、随机还是顺序读写、IO大小等等。
IOMeter也是不错的测试磁盘性能的工具,比如可以测试I/O的传输速度和平均的I/O响应时间。
IOZone是一个文件系统基准测试工具,可以测试不同的操作系统中文件系统的读写性能。
Bonnie++是基于Linux平台的开源磁盘IO测试的工具,可以用它来测试磁盘和文件系统的I/O性能。
hdparm可以用来作跳过文件系统的纯硬件操作测试。
iostat这个工具可以查看进程发出IO请求的数量、系统处理IO请求的耗时、磁盘的利用率等,也可以分析进程与操作系统的交互过程中IO方面是否存在瓶颈。
存储系统,顾名思义,是用来存放我们各种程序和服务的数据。随着现代互联网服务的大数据化,几乎所有的业务都离不开存储系统的支持。
各种存储系统的基础是传统硬盘或者固态硬盘,这两种硬盘在成本、性能、大小方面各有千秋。我想起了宋代有首诗叫《雪梅》,里面比较了白雪和梅花的优缺点:
“梅须逊雪三分白,雪却输梅一段香。”
这句诗用来形容传统硬盘和固态硬盘的关系还挺合适的。
在实际使用中,我们要注意它们的性能优缺点,从而适当来作取舍。比如,如果系统对IOPS或者延迟要求很高,恐怕只有SSD才能满足要求。反之,如果数据量极大需要降低成本,那么只能选择磁盘或者磁带系统了。
你对SSD这种新型存储了解多少?你公司里面有没有系统使用SSD?它们碰到的性能问题有哪几个方面?运维和开发人员是怎么一起解决这些问题的?
欢迎你在留言区分享自己的思考,与我和其他同学一起讨论,也欢迎你把文章分享给自己的朋友。