磁盘I/O那些事

少于 1 分钟读完

在设计存储系统时,磁盘是最常用的存储介质,了解磁盘的各种特性才能高效的管理磁盘,提高系统性能。这篇文章准备介绍磁盘的基本知识,特性,优化技巧,和常见设计方法。

磁盘物理结构

磁盘主要结构为盘片和磁头。一个磁盘中往往包含多个盘片和磁头。盘片被组织磁道,磁道是单个盘片上的同心圆。所有盘面上半径相同的磁道构成了柱面。实际数据都存储在盘面上,通过磁头将数据写入到盘面上。磁盘的结构如下:

disk

磁道上又划分出很多的扇区,扇区大小固定,往往为512字节。柱面,磁道,扇区结构如下图:

disk-1

早期的硬盘每磁道扇区数相同,此时由磁盘基本参数可以计算出硬盘的容量:存储容量=磁头数 * 磁道(柱面)数 * 每道扇区数*每扇区字节数。由于每磁道扇区数相同,外圈磁道半径大,里圈磁道半径小,外圈和里圈扇区面积自然会不一样。同时,为了更好的读取数据,即使外圈扇区面积再大也只能和内圈扇区一样存放相同的字节数(512字节)。这样一来,外圈的记录密度就要比内圈小,会浪费大量的存储空间。 如今的硬盘都使用ZBR(Zoned Bit Recording,区位记录)技术,盘片表面由里向外划分为数个区域,不同区域的磁道扇区数目不同,同一区域内各磁道扇区数相同,盘片外圈区域磁道长扇区数目较多,内圈区域磁道短扇区数目较少,大体实现了等密度,从而获得了更多的存储空间。

影响硬盘性能的因素

影响磁盘的关键因素是磁盘服务时间,它由寻道时间、旋转延迟和数据传输时间三部分构成。理解这一点对设计磁盘读写很重要。

1.寻道时间

寻道时间是指将读写磁头移动至正确的磁道上所需要的时间。寻道时间越短,I/O操作越快,目前磁盘的平均寻道时间一般在3-15ms。因为寻道比较耗时,在设计时往往要减少磁盘的随机I/O次数。

2.旋转延迟

旋转是指盘片旋转将请求数据所在的扇区移动到读写磁盘下方所需要的时间。旋转延迟取决于磁盘转速,通常用磁盘旋转一周所需时间的1/2表示。比如:7200rpm的磁盘平均旋转延迟大约为60*1000/7200/2 = 4.17ms,而转速为15000rpm的磁盘其平均旋转延迟为2ms。

3.数据传输时间

数据传输时间是指完成传输所请求的数据所需要的时间,它取决于数据传输率,其值等于数据大小除以数据传输率。目前IDE/ATA能达到133MB/s,SATA II可达到300MB/s的接口数据传输率,数据传输时间通常远小于前两部分消耗时间。

衡量性能的指标

机械硬盘的连续读写性能很好,但随机读写性能很差,这主要是因为磁头移动到正确的磁道上需要时间,随机读写时,磁头需要不停的移动,时间都浪费在了磁头寻址上,所以性能不高。衡量磁盘的重要主要指标是IOPS和吞吐量。

1.IOPS

IOPS(Input/Output Per Second)即每秒的输入输出量(或读写次数),即指每秒内系统能处理的I/O请求数量。随机读写频繁的应用,如小文件存储等,关注随机读写性能,IOPS是关键衡量指标。可以推算出磁盘的IOPS = 1000ms / (Tseek + Trotation + Transfer),如果忽略数据传输时间,理论上可以计算出随机读写最大的IOPS。常见磁盘的随机读写最大IOPS为:

7200rpm的磁盘 IOPS = 76 IOPS 10000rpm的磁盘IOPS = 111 IOPS 15000rpm的磁盘IOPS = 166 IOPS

从上面可以看出磁盘的IOPS较小。

2.吞吐量

吞吐量(Throughput),指单位时间内可以成功传输的数据数量。顺序读写频繁的应用,如视频点播,关注连续读写性能、数据吞吐量是关键衡量指标。它主要取决于磁盘阵列的架构,通道的大小以及磁盘的个数。不同的磁盘阵列存在不同的架构,但他们都有自己的内部带宽,一般情况下,内部带宽都设计足够充足,不会存在瓶颈。

Page Cache层

在操作系统和磁盘之间,有一层Page Cache,主要用来缓存磁盘上的数据,这样就可以提高操作系统对磁盘的访问速度,但坏处是断电时可能造成一些数据不一致。 Cache层在内存中缓存了磁盘上的部分数据。当数据的请求到达时,如果在Cache中存在该数据且是最新的,则直接将数据传递给用户程序,免除了对底层磁盘的操作,提高了性能。Cache层也正是磁盘IOPS为什么能突破200的主要原因之一。 在Linux的实现中,文件Cache分为两个层面,一是Page Cache,另一个Buffer Cache,每一个Page Cache包含若干Buffer Cache。Page Cache主要用来作为文件系统上的文件数据的缓存来用,尤其是针对当进程对文件有read/write操作的时候。Buffer Cache则主要是设计用来在系统对块设备进行读写的时候,对块进行数据缓存的系统来使用。 磁盘Cache有两大功能:预读和回写。预读其实就是利用了局部性原理,具体过程是:对于每个文件的第一个读请求,系统读入所请求的页面并读入紧随其后的少数几个页面(通常是三个页面),这时的预读称为同步预读。对于第二次读请求,如果所读页面不在Cache中,即不在前次预读的页中,则表明文件访问不是顺序访问,系统继续采用同步预读;如果所读页面在Cache中,则表明前次预读命中,操作系统把预读页的大小扩大一倍,此时预读过程是异步的,应用程序可以不等预读完成即可返回,只要后台慢慢读页面即可,这时的预读称为异步预读。任何接下来的读请求都会处于两种情况之一:第一种情况是所请求的页面处于预读的页面中,这时继续进行异步预读;第二种情况是所请求的页面处于预读页面之外,这时系统就要进行同步预读。 回写是通过暂时将数据存在Cache里,然后统一异步写到磁盘中。通过这种异步的数据I/O模式解决了程序中的计算速度和数据存储速度不匹配的鸿沟,减少了访问底层存储介质的次数,使存储系统的性能大大提高。

基于磁盘特性的设计技巧

1.采用追加写

在进行系统设计时,良好的读性能和写性能往往不可兼得。在许多常见的开源系统中都是优先在保证写性能的前提下来优化读性能。那么如何设计能让一个系统拥有良好的写性能呢?一个好的办法就是采用追加写,每次将数据添加到文件。由于完全是顺序的,所以可以具有非常好的写操作性能。追加写省去了磁头移动和旋转的时间,所以性能特别好。但实际中磁盘完全实现追加写是特别困难的。往往通过合并I/O操作,进行批量提交尽量实现追加写。

2.文件合并和元数据优化

知名的TFS和HayStack都采用了这种技术。小文件合并为大文件后,首先减少了大量元数据,提高了元数据的检索和查询效率,降低了文件读写的I/O操作延时。其次将可能连续访问的小文件一同合并存储,增加了文件之间的局部性,将原本小文件间的随机访问变为了顺序访问,大大提高了性能。同时,合并存储能够有效的减少小文件存储时所产生的磁盘碎片问题,提高了磁盘的利用率。最后,合并之后小文件的访问流程也有了很大的变化,由原来许多的open操作转变为了seek操作,定位到大文件具体的位置即可。在这种设计中,往往需要一个索引文件记录关键的元数据信息,主要为偏移和文件大小,省去了一些冗余属性如访问时间,用户表示等等,因此可以将索引信息放入到内存中,访问更加高效。

分类:

更新时间: