我们来对我们平时最常见的Hard Disk Drives 来进行理解和分析。
首先,我们先介绍一下HDD的几个重要的组成部分:
**sector:**我们的HDD由0-N个sector组成(每个sector的容量在512KB),实际上一个HDD的寻址空间也直接和你的sector数量有关,有N个sector。那么,磁盘的寻址空间也就是0-N。
disk head: 我们实际访问磁盘sector的装置,即disk head移动到的地方,才可以进行数据的读写。
disk arm: 控制磁头到不同的扇区的磁臂。
track: 磁道,即每一个磁盘都是由好几个磁道组成,每一个磁道都是一个个同心圆,磁道上面布满了许多的sector。
这就是我们普通的Hard Disk Drives的几个最基本的部分。接下来,我们以最简单的图片来展示HDD的基本模型:
黑色的地方是磁头,灰色的地方是磁臂,然后磁道以逆时间来进行旋转。
磁头寻找我们的sector的方式
既然磁盘有多个磁道,那么我们寻找的sector的步骤也就基本可以分为三步:
- 寻道:即通过摆动磁臂来使磁头落在正确的磁道上。
- 寻sector:磁道通过旋转来使磁头找到正确的sector。
- 写\读数据:通过磁头来进行读写数据的操作。
有一些磁盘寻道的细节需要注意:1. 一些磁盘有偏移跟踪的相关功能。即我们的磁头在读取数据的时候,可能不会直接读到准确的sector位置。为了防止出现了偏移而导致的需要多增加旋转一圈的延迟。如下图所示:
还有一点,现代的磁盘都具备自己的cache,叫做track buffer。容量大约在8~16MB。磁盘cache存储的即是从读头读出的数据。当然,这种做法也会带来一个问题:就是写回数据的时候,你不知道是写进了cache还是真正写进了磁盘中。这个区别被称为write back和write through的问题。
访问磁盘的时间消耗建模
T
t
o
t
a
l
=
T
s
e
e
k
+
T
r
o
t
a
t
i
o
n
+
T
t
r
a
n
s
f
e
r
T_{total}=T_{seek}+T_{rotation}+T_{transfer}
Ttotal=Tseek+Trotation+Ttransfer
其中
T
t
r
a
n
s
f
e
r
T_{transfer}
Ttransfer 表示磁头找到sector开始读写数据的时间。
这三个模块大概的平均时间如下:
(这里需要补充一点rotation的Average Rotation的时间通常是Full Rotation Time 的1/3,这个通过计算得到,计算的基本公式即是:把所有可能的差别长度/寻道的所有可能组合),具体如下所示:
可以看到寻道时间和寻找时间都比转移数据的时间高了一整个数量级,所以
T
t
r
a
n
s
f
e
r
T_{transfer}
Ttransfer的时间可以忽略不记。
这也就是我们磁盘随机访问的时间会远大于顺序访问(因为随机访问会增加大量的寻找道时间),具体的倍数关系如下所示:
正是因为磁盘的随机访问时间远大于顺序访问。所以下面要讨论的磁盘调度算法才是我们所要关注的重点。
磁盘访问调度算法
磁盘访问调度算法基本分为三大类:
- SSTF: Shortest Seek Time First
即所基于的是贪心策略,在所有访问请求中,选取每次寻道时间都能最短的请求(离的最近的块)来执行。
但是这种策略会带来某些block starvation的情况,因为如果某些块在外圈,离得都比较远的话。那可能一直都不会被访问到了。
针对这种starvation的问题。
2. Scan:C-Scan or F-Scan
基于扫描策略的磁盘访问算法。
F-Scan的基本思路就是从每次从外圈一直访问到内圈,再从内圈访问到外圈。这样一直循环往复。
S-Scan的基本思路就是单方向的访问,即是每次要么都是从外圈到内圈,要么都是从内圈到外圈。
这种扫描的策略相当于进程调度的轮转调度的思路。这种调度方案也就代表无法基于寻道时间来对性能进行优化。
- SPTF: Shortest Positioning Time First
这种寻道方法通过是直接在磁盘内部实现,而不是OS上实现。原因是OS无法直接获取到磁盘内部的磁道距离数据以及block距离数据。基本原理也是看 T s e e k T_{seek} Tseek和 T r o t a t i o n T_{rotation} Trotation的时间差再做选择。
还有一点要注意的就是,请求OS中对访问请求进行merge的相关操作,比如我的访问sector分别是4,25,5。OS肯定把4,5 merge到一起,以此来减少相关寻道的时间。