大家都知道硬盘的随机IO很慢,但是比顺序IO慢多少,不知道大家有没有直接对比一下在数字中。今天我就来实际进行一次压测,比较磁盘在顺序IO和随机IO不同场景下的性能数据。通过今天的实验数据,你会深刻理解为什么数据库事务要用日志,索引为什么要用节点更大的B+树。对于任何存储系统,性能指标无非是带宽、延迟或IOPS。我的测试机的硬盘配置是RAID5,由7块300G万转机械盘组成。压测工具使用fio。在压力测试的时候,我们固定了几个参数:IOengine我们选择libaio,避免操作系统管理PageCache内存干扰测试结果,使用直接参数绕过unified_rw_reporting的开启,让结果读写分开显示。为了保证测试比较准确,我们将运行时间设置为300s。由于服务器的敏感性,压测对象不选择裸机。使用会有一点文件系统开销。测试文件大小定义为100G,我的RAID卡缓存为1G。目的是让它的命中率不至于过高。作为调度策略,我们选择最常用的noop开启refill_buffers。每次我/O提交后,都会重新生成测试文件数据片段,保证随机性。遵循RAID使用配置建议,关闭磁盘自身缓存,然后动态调整其他参数,再进行多次对比测试。读取和随机读取分别验证磁盘IO单元我们使用扇区的整数倍,5121K2K...RAID卡预读策略,设置NORA(不开启预读)和RA(开启预读))独立测试顺序对于读测试,我们先来看磁盘阵列在顺序读情况下的带宽表现,如图1所示:可以看出,当IOsize比较小的时候,即使连续IO请求顺序发起,带宽性能不高。太棒了,不到20MB/s。随着IO大小的增加,带宽也随之增加,最大可以达到1.2GB以上。请注意,以NORA为例,当带宽从128K增加到256K时,带宽突然增加了很多。为什么是这样?秘诀是我的RAID阵列中的条带大小是128K。当IO大小为256K时,磁盘阵列开始并行工作。IOsize小的时候,就不能利用多盘了。/opt/MegaRAID/MegaCli/MegaCli64-LDInfo-Lall-aALL......StripSize:128KB另外,对于顺序IO,RA预取也可以起到作用,当IO大小为64k时可以达到1.2GB的带宽。我们再来看延迟,如图2所示:我们图中的单位是微秒-us。在《简单聊聊磁盘分区》中,我对磁盘耗时做了一个理论估算。磁盘耗时主要在两个地方:寻道时间:3-15ms,这个耗时可以通过合理分区优化旋转延迟:万转磁盘的延迟大概在0-6ms。为什么在图2的实验结果中,延迟很低。当IO大小为512时,平均值竟然只有30us左右?其实在顺序IO的情况下,RAID卡的缓存命中率是非常高的。事实上,大部分的读请求并没有穿透让磁盘的机械轴工作。再来看IOPS,如图3所示:当IO请求大小刚好是一个扇区大小时,磁盘阵列的IOPS性能最高,达到每秒3W以上。当IOsize增加时,IOPS逐渐降低,但此时磁盘吞吐量实际上是在增加的。综上所述,顺序IO情况下磁盘阵列的性能还是很不错的。原因有以下三点:在顺序IO的情况下,RAID卡的命中率高,尤其是设置了RAID预取的情况下。舒适的状态,因为它省去了寻求的延误。当IO超过RAID条带大小时,IO会被分配到多个磁盘并行处理。随机读测试我们作为开发者在使用磁盘的时候,不一定能保证你总能让它工作在最舒服的状态,有时候你可能不得不让它进行随机存取。所以今天我们也试试我的磁盘阵列在随机情况下的性能。对于fio工具,我们只需要将rw参数设置为randread即可。不过我只测试了IO大小到128就停了,因为越大越像顺序IO。我们先看带宽,如图4所示:即使机械硬盘组成RAID阵列,有缓存,似乎也与随机IO无关。在随机IO的情况下,带宽吞吐量惨不忍睹。当IO大小比较小时,每秒只有零点几兆。我们再来看延迟,如图5所示:在随机情况下,延迟基本在5ms左右,符合我们之前的理论计算结果。随机访问导致更多请求实际穿透机械开关。再看IOPS,这个指标也很差,200左右。这个数据与图5中的延迟相呼应,如果一个请求处理5ms左右,那么一秒只能处理200次左右。所以硬盘厂商天天给你吹,说他们的磁盘IOPS能到几万。但是他们从来不说随机IO的情况,其实也就200个而已。大家看到我的10000转的机械硬盘组成RAID5阵列了。在最好的序列条件下,带宽可以达到1GB/s以上,平均时延也很低,最低只有20多us。但是在随机IO的情况下,机械硬盘的缺点就暴露无遗了。零点几兆的带宽,近5ms的延迟,IOPS只有200左右,原因是随机访问直接让RAID卡缓存一个显示盘,不能并行,因为我机器的RAIDwidthStripSize为128KB,机械轴必须在轨道之间跳转。了解了几十兆甚至上千兆磁盘顺序IO的带宽后,随机IO真是少得可怜。结语从上面的测试数据可以看出机械硬盘在顺序IO和随机IO下的巨大性能差异。在顺序IO的情况下,磁盘最擅长顺序IO,Raid卡的缓存命中率也高。这时候的带宽性能是几十上百M,最好的情况下甚至可以达到1GB。此时IOPS可以在2-3W左右。在随机IO的情况下,机械轴也被迫跳来跳去寻道,RAID卡缓存也失效。带宽已经降到1MB以下,最低只有100K,IOPS也只有200左右。如果你真正理解了上面实验中的数据,那么在很多工程实践中你就能明白很多东西。复制文件夹:我们都知道,在复制文件夹的时候,如果文件夹里有很多一堆破文件,这时候复制就很慢了。原因是这个时候机械硬盘最有可能在做随机IO。如何提高复制速度?很简单,先把它们放在一个包里就可以了。打包后,这个文件夹就变成了一个大文件。如果此时再copy一次,磁盘最擅长顺序IO,所以会快很多。数据库事务:所有数据库在实现事务时,都必须保证写入的数据在返回前成功落盘。但是为什么他们几乎都是写入自己的事务日志文件后返回成功,而不是直接写入数据表文件。这背后的原因是磁盘读写的性能。事务只需要保证数据成功落地,写到哪里都无所谓。如果是写入数据文件,很大概率会变成随机IO。如果是写入日志文件,就是不折不扣的顺序IO,性能会发挥到极致。MysqlB+树:从上面的数据也可以看出,无论是顺序IO还是随机IO,只要增加每次IO的单位,性能就会有所提升。明白了这一点,你才能真正理解为什么Mysql使用B+树作为索引,而不是其他树(比如二叉树)。因为B+树的节点更大,IO会让磁盘工作的更舒服。最后分享一个我5年前项目中的实际性能优化案例。当时接手一个系统,用百万用户imei查询Mysql中用户的另一个字符串id(clientid)数据。之前开发的实现方式是传统的Mysql语句批量查询。在这种实现下,不说多次耗时的网络RTT,单说Mysql查询,即使此时有索引,此时也必须进行大量的随机IO,因为用户imei是随机分配的。我采用的优化方法也很简单。我直接通过顺序IO一次性把Mysql用户的整个user表读出来,加载到内存中。在内存中用HashTable组织起来,通过Hash进行快速查询。最终优化耗时减少了90%以上。练内功练硬盘特技:1、开盘:剥去机械硬盘的硬外衣!2.磁盘分区也暗示技术水平。3、机械硬盘速度慢,容易坏,如何解决?4.拆解SSD结构5.一个新的空文件占用多少磁盘空间?6.一个只有1字节的文件实际占用多少磁盘空间?7、为什么文件太多时ls命令会卡住?8.理解格式化原理9.读取文件一个字节实际会发生多少磁盘IO?10.文件写入一个字节后什么时候开始写磁盘IO?11、机械硬盘的随机IO比你想象的要慢。12、服务器配置固态硬盘比机械硬盘快多少?我的公众号是《练内功》。在这里,我不是简单地介绍技术理论,也不是只介绍实践经验。而是理论联系实际,用实践加深对理论的理解,用理论提高技术实践能力。欢迎关注我的公众号,分享给你的朋友吧~~~
