高级 #os#disk#scheduling#io

磁盘调度

磁盘调度(Disk Scheduling)是操作系统优化磁盘访问顺序的策略——减少磁头移动距离,也就减少了磁盘 I/O 的时间

为什么磁盘访问要调度?

机械硬盘(HDD)读取一个数据的时间:

访问时间 = 寻道时间 + 旋转延迟 + 传输时间
             │           │           │
         移动磁头     等待扇区      读取数据
         到目标磁道   旋转到磁头下
             │           │           │
          ~5-10ms     ~4-8ms      ~0.1ms

💡 寻道占据了磁盘访问时间的大头——所以磁盘调度的核心目标就是尽量减少磁头移动距离。

磁盘调度就是决定多个 I/O 请求的执行顺序,使磁头移动总距离最小。

🏫 类比:图书馆取书 你在图书馆接到 10 个取书单,分布在 10 个不同书架上:

  • 随机取:A 区 → Z 区 → B 区 → Y 区 → …(来回跑断腿)
  • 排序取:A 区 → B 区 → … → Z 区(一趟走完)

经典磁盘调度算法

1. 先来先服务(FCFS)

按到达顺序处理请求。

磁道请求:98, 183, 37, 122, 14, 124, 65, 67
当前磁头位置:53

磁头移动:
53 → 98 → 183 → 37 → 122 → 14 → 124 → 65 → 67
  +45  +85  +146  +85  +108  +110  +59   +2
总移动:640 个磁道

优点:公平,简单 缺点:磁头来回跑,效率极低

2. 最短寻道优先( SSTF / SSF)

选择离当前磁头最近的请求先处理。

当前在 53:
离 53 最近的请求是 65(差 12)→ 先处理 65
然后离 65 最近的请求是 67(差 2)→ 先处理 67
然后离 67 最近的是 37(差 30)→ 处理 37
...

SSTF 顺序:53 → 65 → 67 → 37 → 14 → 98 → 122 → 124 → 183
移动:    +12  +2  +30  +23  +84  +24  +2   +59
总移动:236 个磁道(比 FCFS 的 640 好很多!)

问题饥饿——如果不断有近处的请求到来,远处的请求可能永远得不到服务。

3. SCAN(电梯算法)

磁头沿一个方向移动,一路处理经过的请求,到终点后折返。

磁头从 53 开始向内移动→
53 → 37 → 14 (向内到 0)→ 折返 → 65 → 67 → 98 → 122 → 124 → 183

移动:53→0 + 0→183 = 53 + 183 = 236

优点:无饥饿,性能较好 缺点:刚经过的请求要等磁头从终点折返回来

4. C-SCAN(循环 SCAN)

磁头只沿一个方向处理请求,到终点后快速折返到起点(不处理请求),重新开始。

53 → 65 → 67 → 98 → 122 → 124 → 183 →(快速回到 0)→ 14 → 37

移动:53→183 + 183→0 + 0→37 = 130 + 183 + 37 = 350

优点等待时间更均匀——所有磁道的等待时间近似相等

💡 C-SCAN 适合负载均衡的场景——数据库、文件服务器等需要公平对待所有 I/O 请求的系统。

算法对比

算法总寻道距离公平性饥饿适用场景
FCFS最长✅ 最好低负载
SSTF较短❌ 不均⚠️ 可能响应时间优先
SCAN较短✅ 较好通用
C-SCAN中等✅✅ 最好均衡负载
LOOK✅ 好SCAN 改进(不到终点就折返)

LOOK 和 C-LOOK

LOOK 是 SCAN 的改进——磁头不一定要移动到磁盘端点,只移动到最远请求的位置就折返。

SCAN:53→0(到端点)→183(到端点)
LOOK:53→14(最内请求)→183(最外请求)

C-LOOK 同理——C-SCAN 的改进,只到最外请求就折返。

💡 现代调度器实际使用的是 LOOK/C-LOOK——Linux 内核的 CFQ(完全公平排队)和 deadline 调度器都实现了类似算法。

SSD 为什么不需要磁盘调度?

SSD(固态硬盘) 没有磁头,访问任何位置的延迟都是均匀的(~0.1ms)。

HDD 访问时间 = 寻道 + 旋转 + 传输 = 5-15ms
SSD 访问时间 = 传输 = 0.05-0.1ms

但是 SSD 需要别的调度:

  • TRIM:通知 SSD 哪些块已不再使用,SSD 内部可以提前擦除
  • 磨损均衡:将写入分布到所有闪存块,延长寿命
  • 垃圾回收:回收已删除块的空间

💡 Linux 在 SSD 上仍然有 I/O 调度器——不是为了优化寻道,而是为了合并请求和 QoS(服务质量)。

Linux I/O 调度器

# 查看当前 I/O 调度器
$ cat /sys/block/sda/queue/scheduler
mq-deadline kyber [bfq] none

# 切换调度器
$ echo kyber > /sys/block/sda/queue/scheduler
调度器类型适用场景
mq-deadline多队列 + 截止时间通用场景
BFQ完全公平排队桌面交互(低延迟)
Kyber自适应快速设备(NVMe SSD)
none无调度高性能 NVMe(直接让硬件处理)

算法对比:同一工作负载下的性能

用前面的示例请求(98, 183, 37, 122, 14, 124, 65, 67),起始磁头位置 53:

算法总移动距离特点
FCFS(先来先服务)640 个磁道公平但低效——来回跑
SSTF(最短寻道优先)约 236 个磁道比 FCFS 快 ~2.7 倍——但可能”饿死”远处请求
SCAN(电梯算法)约 208 个磁道最均衡——无饥饿,性能好
C-SCAN(循环电梯)约 383 个磁道比 SCAN 多走了”折返路程”——但等待时间更均匀

取书员的视角

  • FCFS = 哪个单子先来就去取哪本——在 A 区→Z 区→B 区来回跑
  • SSTF = 永远去最近的”那本书”——近的总是优先,远处的书等很久
  • SCAN = 从东走到西,一路顺手取——走一趟取完所有

小结

概念要点
磁盘调度的目标最小化寻道时间,提高吞吐量
SSTF选最近的先做(可能饥饿)
SCAN / LOOK电梯算法,一个方向走到底(无饥饿)
C-SCAN / C-LOOK单向 + 快速折返(等待时间均匀)
SSD无寻道开销,但需要 TRIM 和磨损均衡
Linux 调度器mq-deadline(通用)、BFQ(交互)、Kyber(NVMe)

为什么先学这个? 磁盘调度是 I/O 子系统的核心优化——理解了它,你就知道为什么 SSD 让服务器 I/O 性能飞跃。接下来转向 I/O 的更大图景:I/O 硬件与驱动模型