聊聊磁盘

436 阅读3分钟

博客索引

磁盘的速度比内存大约慢了三个数量级,低速的主要原因是因为磁盘是一种机械装置。

磁盘结构可以参考存储器层次结构

磁盘以扇区的大小的块来读写数据。对扇区的访问时间主要有三部分:寻道时间、旋转时间和传送时间。

  • 寻道时间:为了读取某个目标扇区的内容,传动臂首先将读/写头定位到包含目标扇区的磁道上。通常花费时间为3-9ms。一次寻道的最大时间可以高达20ms。

  • 旋转时间:一旦读/写头定位到了期望的磁道,驱动器等待目标扇区的第一个位旋转到读/写头下。最大旋转延迟是(以秒为单位)T(max rotation) = (1/RPM)*(60/1min) RPM:磁盘每分钟转速

  • 传送时间:当目标扇区的第一个位位于读写头下是,驱动器就库读取该扇区的内容。T = (1/RPM)(1/(平均扇区数/磁道))(60/1min)

假如有如下参数磁盘:

RPM: 7200RPM

T(寻道): 9ms

每条磁道平均扇区数:400

那么对于这个磁盘来说:

平均旋转延迟(以ms为单位)是

T(avg rotation)= 1/2 *T(max rotation) = 1/2 * (60s/7200RPM) * 1000ms/s ≈4 ms

平均传送时间是

T (avg transfer) = 60/7200RPM * (1/400扇区/磁道 )* 1000ms/s ≈0.02 ms

总之,整个访问时间估计为:

T (access)= T(avg seek) + T(avg rotation)+ T (avg transfer) =9ms +4ms+0.02ms =13.02ms

这个例子说明了一些很重要的问题:

  1. 因为寻道时间和旋转延迟大致相等,所以将寻道时间乘2是顾及磁盘访问时间的简单而合理的方法。

  2. 访问一个磁盘扇区中的512字节的时间主要是寻道时间和旋转时间。访问山区中第一个字节用了很长时间,但是访问剩下的字节几乎不用时间

第二点结论很重要,这就是说明了磁盘的顺序读写的性能要远远大于随机读写。

比如有50个读请求,顺序读的时间基本上等于一次寻道时间+一次旋转时间,花费13ms。而随机读的话,花费的时间等于50次寻道时间+50次传送时间,花费50*13ms =650ms。写请求同理。当然这里只是举个例子为了说明随机读写性能远不如顺序读写。实际情况中,操作系统不会这么干。会将随机请求进行预处理,进行合并和排序(这里的排序涉及到一个电梯算法,有兴趣的自行百度)放入一个队列,整个请求队列按照磁盘扇区增长的排列。这种优化减少了请求,而且通过保持磁盘头以直线方式移动,缩短了所有请求的磁盘寻址时间。

从这里联想:一些中间件为了提高数据持久化的性能,想方设法的吧数据顺序写入文件,从而利用磁盘的顺序读写特性,来最大限度的压缩磁盘的性能。

比如说数据库MySQL,写数据之前,会先将redo日志顺序写入磁盘,从而保证数据的持久化。而真正的将数据刷到磁盘中是由另外的线程会将脏页的数据刷到磁盘(这里是操作系统来执行的),这样子就利用到了磁盘顺序读写的特性。

还有ROCKETMQ也是一样,将数据顺序写入到commitlog中,然后在刷到磁盘中,同步状态下跟MySQL异曲同工。

参考:

《深入理解计算机系统》

《Linux内核设计与实现》