阅读分享 -- 《Linux 系统编程 第二版》IV

书接上回III 这里我们要分享的时磁盘部分。阅读分享 -- 《Linux 系统编程 第二版》III|ZklMao-Space (zklkk.online)

概述

今天分享的磁盘I/O部分,这部分内容不是很多。文章分享顺序大概是这样的: 磁盘基本结构 - 磁盘工作原理 - 磁盘I/O 调度算法简单介绍 - 杂项

磁盘基本结构

这里的磁盘泛指早期连接在南桥的低速设备机械式硬盘和固态硬盘。

机械硬盘

机械硬盘基本结构由主控电路、机械臂、磁头、盘片、高速电机组成。大致结构见下图:

固态硬盘

固态硬盘基本结构由主控芯片和、缓存芯片和闪存芯片组成,大致结构见下:

image-ymby.png

磁盘工作原理

机械磁盘和固态磁盘的共组原理是不一样的这里分开分享:

机械硬盘

基本概念

  • 盘片(Platters):
    盘片是机械硬盘的存储组件,通常是由金属或玻璃材料制成的圆形碟片,盘片的正反两面会涂有磁性物质。硬盘的每一个盘片都有两个盘面(Side),即上下盘面,一般每个盘面都会利用,都可以存储数据,成为有效盘片,也有极个别的硬盘盘面数为单数。每一个这样的有效盘面都会有盘面号,按顺序从上至下从“0”开始依次编号。在硬盘系统中,盘面号又叫磁头号,因为每一个有效盘面都有一个对应的读写磁头。硬盘的盘片组在2~14片不等,通常有2~4个盘片,故盘面号(磁头号)为0~3或0~7。我们的数据会以二进制方式被存储在盘片的上下两面里。
  • 磁道(Tracks):
    磁盘在格式化时被划分成许多同心圆,这些同心圆轨迹叫做磁道(Track)。磁道从外向内从0开始顺序编号。每一个盘面有300~1024个磁道,新式大容量硬盘每面的磁道数更多。每个磁道又被划分为若干个扇区,而信息以脉冲串的形式记录在这些轨迹中。
  • 扇区(Sectors):
    在磁盘里的磁道上等分出若干个弧段,这些弧段便是磁盘的扇区,每个扇区可以存放512个字节或4KB(通常情况下是512字节),磁盘驱动器在向磁盘读取和写入数据时,要以扇区为单位。通常扇区与扇区之间也有一定间隔(逻辑上的间隔,物理上没有任何间隔,但是每个扇区的开头都有一个同步信息,外围电路可以用来判断一个扇区的开始)
  • 簇(Cluster):
    将相邻的若干个扇区称为了一个簇。操作系统读写磁盘的基本单位是扇区,而文件系统的基本单位是簇。
    簇越大存储性能越好,但空间浪费严重。簇越小性能相对越低,但空间利用率高。FAT32格式的文件系统簇的大小默认为4K。
  • 柱面(Cylinder):
    它是指将每个盘片对应的磁道垂直堆叠起来,形成一个虚拟的圆柱体,这个堆叠的圆柱从外向内,分别为0柱面、1柱面...N柱面,越往内柱面的同心圆越小。每个圆柱上的磁头由上而下从“0”开始编号。数据的读/写按柱面进行,即磁头读/写数据时首先在同一柱面内从“0”磁头开始进行操作,依次向下在同一柱面的不同盘面即磁头上进行操作,只在同一柱面所有的磁头全部读/写完毕后磁头才转移到下一柱面,因为选取磁头只需通过电子切换即可,而选取柱面则必须通过机械切换。电子切换相当快,比在机械上磁头向邻近的磁道移动快得多,所以数据的读/写按柱面进行,而不按盘面进行。也就是说,一个磁道写满数据后,就在同一柱面的下一个盘面来写,一个柱面写满后,才会机械的将磁头移到下一个扇区开始写数据。读数据也按照这种方式进行,这样就提高了硬盘的读/写效率。当计算机需要读取或写入磁盘上的数据时,它会根据柱面号、磁头号和扇区号来确定目标数据的位置。通过控制磁头的移动和盘片的旋转,计算机可以准确地定位到特定柱面上的特定扇区,进行数据的读写操作。
  • 磁头(Read/Write Head):
    磁头是用于读取和写入数据的装置,一般盘片的上下都有磁头,位于磁头臂上,每个磁头上都有读和写的操作装置。
  • 磁头臂(Actuator Arm):
    磁头臂是支持磁头的可移动臂,通过电动机或电磁力控制,可以使磁头在盘片上移动到不同的磁道位置。

image-qiln.png

image-zpsr.png

大致工作原理

可用(柱面号,盘面号,扇区号)来定位任意一个“磁盘块”。操作系统读取文件元信息获取文件数据存放在外存中的几号块(这个块号就可以转换成(柱面号,盘面号,扇区号)的地址形式)并将这个请求通过驱动程序转换为带有协议格式的电信号驱动硬盘,硬盘主控解码信号后进行寻址(寻道)读取/写入完成操作系统的操作。

固态硬盘

基本结构及概念

  • 主控:一种嵌入式微芯片,SSD的大脑,负责发出SSD工作所需的所有指令。
  • NAND闪存:SSD中存储数据的地方。
  • DRAM:内存,存储SSD中的地址映射等信息。

image-loos.png

一个固态硬盘上有多个NAND闪存,主控通过若干个通道并行控制多个NAND闪存,大大提高底层的带宽。NAND闪存(即Flash)由多个Block组成,一个Block内部又有多个Page(物理页),Page里才是我们保存的数据。

Flash的特性一:Page是SSD存取数据的最小单位,每次存取数据至少是一个Page,每个page的大小为4k或者8k。
Flash的特性二:Page可以被读写,但是不能被覆盖,数据只能被写入到空Page中,如果要使用有数据的Page则必须先清空Page中的数据。但Page是不能被单独清空的,Flash清空操作的最小单位是Block,即每次清空至少一个Block。

基本工作原理

  • mapping table (映射表)

在SSD中,一般会维护一个mapping table,维护逻辑地址到物理地址的映射。每次读写时,可以通过逻辑地址直接查表计算出物理地址,与传统的机械磁盘相比,省去了寻道时间和旋转时间。机械硬盘定位数据的时间大约在几毫秒到十几毫秒左右,而固态硬盘定位数据只需要约0.1ms左右,所以在随机读写上固态硬盘的速度远远高于机械硬盘。

写入

固态写入数据分为两种情况:

新页写入
  1. 找到一个空闲的Page
  2. 把数据写入空闲的Page
  3. 在mapping table中新增逻辑地址与物理地址的映射关系
覆盖页写入
  1. 准备内容,如果是更新数据的话,要把原Page中的内容都读出来,不能只有更新的部分
  2. 找到一个空闲的Page
  3. 把数据写入空闲的Page
  4. 更新mapping table,把逻辑地址的映射改成新的Page(这样原来的Page就在mapping table中废弃了)
读取

SSD的读取流程比较简单,分为两步。

  1. 在mapping table中搜索数据所在的Page
  2. 读取Page中的数据
    这里的第一步对应机械硬盘中的物理定位(寻道和旋转),第二部对应的机械硬盘中的数据读取。
    在这两个步骤中,SSD的性能都要远高于机械硬盘。特别是在第一步中,相比机械硬盘的机械运动,SSD的数据定位方式要快上几十倍甚至百倍。

磁盘I/O调度算法

SSD 中的负载均衡算法

这个负载均衡算法只有在SSD磁盘中才会出现,因为Nana flash 芯片是由擦写次数寿命的,所有磁盘主控程序一般都有负载均衡算法,目的就一个让固态中的每一个闪存芯片都平均地被擦写避免极端情况出现导致某颗芯片提前寿命用尽导致数据无法写入,从而降低磁盘性能。

调度器的必要性
  • 为减少磁盘寻址次数和移动距离,提高 I/O 性能,操作系统内核实现了 I/O 调度器。
工作机制
  • 合并请求
    • 将多个相邻的 I/O 请求合并为一个,减少 I/O 操作次数。例如,进程先后请求读取磁盘上的连续数据块,调度器会合并这些请求,减少磁盘头移动次数。
  • 排序请求
    • 对 I/O 请求按块号排序,使磁盘头以线性、平滑的方式移动,避免无计划移动和频繁寻址操作。排序后的请求队列更有利于磁盘高效访问。
Deadline I/O 调度器
  • 工作原理
    • 保留传统调度器的有序请求队列,为读和写请求分别维护 FIFO 队列,并为每个队列中的请求设置过期时间。读请求过期时间通常较短,写请求过期时间较长。
  • 优势
    • 有效避免 “写饿死读” 问题,提高系统整体吞吐量,保证请求响应时间。
Anticipatory I/O 调度器 (预读取调度器)
  • 工作原理
    • 处理读请求时,预测下一个读请求可能访问的区域,并提前进行数据预读。若在预测时间内收到下一个读请求,可直接从缓存中返回数据,避免磁盘寻址。
  • 优势
    • 通过预测读请求,减少磁盘寻址次数,提高 I/O 性能,尤其对顺序访问文件效果显著。
CFQ(Complete Fair Queuing)I/O 调度器 (完全公平)
  • 工作原理
    • 为每个进程分配独立队列,每个队列按时间片调度。I/O 调度程序轮流处理每个队列中的请求,确保每个进程公平获得 I/O 资源。
  • 优势
    • 对所有进程公平,避免某些进程长时间占用 I/O 资源,保证系统整体性能。
Noop I/O 调度器(电梯)
  • 工作原理
    • 不进行排序操作,只进行合并操作,适用于不需要排序的特殊设备。

杂项

调度器选择与配置

  • 启动时配置
    • 系统启动时,可通过内核命令参数 iosched指定默认的 I/O 调度器,如 iosched=cfq表示使用 CFQ 调度器。
  • 运行时配置
    • 系统运行时,可通过修改文件 /sys/block/device/queue/scheduler来选择不同的 I/O 调度器,其中 device是具体的设备名称。