硬盘基础知识

硬盘(HDD)主要由盘片、磁头、电机马达、接口等组成。

HDD

盘片(Platters)表面涂有磁性材料,工作时在主轴马达的带动下进行高速旋转(比如每分钟 7200 转)。每个盘片都有上下两面,称为盘面,每个盘面都有一个对应的读写磁头负责读写该盘面上的数据。盘面数与磁头数相等。当关机时,磁头会停留在硬盘的停泊区,工作时才会移动到盘面上方,依靠磁盘高速旋转引起的空气动力效应悬浮在盘面上。在硬盘系统中,盘面按照从上到下的顺序从 0 开始编号,盘面号也叫磁头号,比如一个硬盘有两个盘片,则盘面号为 0 ~ 3。

分解结构1

分解结构2

分解结构3

其中 A 是磁道,B 是扇面,C 是扇区,D 是簇(扇区组)

在盘片高速旋转时保持磁头不动,那么磁头就会在盘面上形成一个圆形的轨迹,这些同心的圆形轨迹就是磁道(Track)。每个盘面上都有多个磁道,这些磁道由外向内从 0 开始顺序编号,磁道之间并不是紧挨着的,因为磁化的单元挨得太近会相互影响。

所有盘面上半径相同的同心磁道垂直堆叠在一起构成的一个圆柱,称为柱面(Cylinder)。柱面是一个抽象出来的概念,它在物理上不是一体的,只是在空间上类似于一个圆柱的外壁。为了方便理解,可以认为柱面就是磁道。柱面上的磁头由上到下从 0 开始顺序编号,数据的读写也是按照柱面进行。在读写数据时,首先在同一柱面内从 0 号磁头开始操作,依次向下在同一柱面的不同盘面即磁头上进行操作,只有当同一柱面的所有磁头全部读写完毕后才将磁头切换到下一个柱面(同心圆往里的柱面)。这么做的原因是选取磁头只需通过电子切换即可,而选取柱面则必须通过机械切换,电子切换是相当快的,而机械切换磁头则要慢得多。概括来说,就是当一个磁道写满数据后,就在同一柱面的下一个盘面上写,一个柱面写满后,才会移动到下一个柱面,读数据也是按照同样的方式。

盘面上可以划分出很多磁道,但是我们并不需要每次都读写这么多数据,所以又将磁道划分为了若干更小的弧段,每段被称为一个扇区(Sector)。由于这些弧段转动的角速度一样,但是长度不同,所以线速度也不一样,外圈的线速度大于内圈,即相同的转速下,在同样的时间段内外圈划过的弧段长度要比内圈划过的弧段长度大。扇区从 1 开始编号,是硬盘进行读写操作的最小单位,一般硬盘的一个扇区大小为 512 字节,这也就意味着哪怕我们只存放 1 字节的数据也会占用硬盘的一个扇区(512 字节)。后来为了提升硬盘的效率和使用率又推出了 4K 大小的扇区标准。

扇区存储的第一个主要部分就是标识符,也就是扇区头标,它是一个扇区的三维地址,包括盘面号、柱面号和扇区号,通过这三个地址可以唯一确定一个扇区。扇区的第二个主要部分就是存储数据的数据段,可分为数据和保护数据的纠错码(ECC)。

容量计算

存储容量 = 磁头数(盘面数)* 磁道数(柱面数)* 每个磁道的扇区数 * 每个扇区的字节数

以前的硬盘每个磁道的扇区数是一样的,外圈扇区的密度小,内圈扇区的密度大。现在的硬盘内外圈扇区的密度一致,这样磁道的长度越长,扇区就越多,存储的数据量就越大。

簇或块

从硬盘的物理结构来看,数据存取信息的最小单位是扇区,一个扇区可能为 512 字节或者是 4K。由于扇区的容量小且数量众多,在寻址时比较困难,所以操作系统就将相邻的扇区组合在一起,形成一个整体,这个整体就是操作系统对硬盘进行存取的最小单位,在 Windows 下称为簇(Cluster),在 Linux 等系统中称为块(Block)。每个簇或块可以包含 2、4、8、16、32 等,2 的 n 次方个扇区。

我在我的这台老设备(Windows 系统)上通过管理员身份运行 fsutil fsInfo ntfsInfo C: 命令,会得到以下信息:

磁盘信息

这台设备使用的文件系统是 NTFS,默认的簇大小为 4096 字节。

访盘过程

当需要从硬盘读取数据时,操作系统会将数据的逻辑地址发送给硬盘,硬盘的控制电路按照寻址逻辑将逻辑地址翻译成物理地址,即确定要读取的数据在哪个磁道,哪个扇区。

为了读取这个扇区的数据,需要将磁头移动到这个扇区的上方,为了实现这一点,首先必须找到对应的柱面,即磁头需要移动到对应的磁道上,这个过程叫做寻道,所耗费的时间叫做寻道时间。然后目标扇区旋转到磁头下,这个过程耗费的时间叫做旋转时间。接下来磁头读取该扇区的信息,然后就需要进行数据传输,即数据从硬盘传输到内存。

可以看到,进行一次读写硬盘所需要的时间可以概括为:寻道时间、旋转时间和传输时间。目前硬盘的平均寻道时间在 3ms 到 15ms 之间,普通硬盘的转速一般为 5400 rpm 或 7200 rpm。

局部性原理与磁盘预读

由于存储介质的特性,硬盘本身的存取速度就比主存慢很多,再加上磁头的机械运动,存取速度就更慢了。为了提高硬盘的效率,尽量减少磁盘 I/O,硬盘往往不是严格的按需存取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序地向后读取一定长度的数据放入内存,这样做的理论依据是计算机科学中著名的空间局部性原理:

当一个数据被用到时,其附近的数据通常也会马上被用到。

程序在运行期间,一段时间内所需要的数据通常都比较集中,由于磁盘的顺序读取效率很高(不需要寻道时间,只需要很少的旋转时间),因此预读一般都可以提高磁盘 I/O 的效率。磁盘预读的长度一般为页(Page)的整数倍。由于操作系统经常与内存和硬盘这两种设备进行通信,为了屏蔽底层物理存储结构的设计细节,需要抽象出一种逻辑上的存储单位。当与硬盘打交道时,操作系统使用簇或者块;当与内存打交道时,操作系统使用页。当程序要读取的数据不在内存中时,会触发一个缺页异常,此时操作系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置然后连续读取一页或者几页的数据放入内存,然后异常返回,程序继续执行。