LabHub
学习 学习路径 课程

计算机组成

存储 — 从旋转的盘片到并行队列

在 LabHub 中继续学习

一句话总结

HDD 必须实际移动磁头,因此随机访问以毫秒计;SSD 没有这一限制,但擦除粒度较大,写入有其独特的成本结构。

流程图: HDD。 · 顺序与随机相差百倍以上 · SSD。 · 设备实际写入量会大于主机请求量

为什么需要了解这些

数据库与文件系统的大量设计都建立在“旋转盘片”这一前提上。顺序访问比随机访问快上百倍,催生了 B 树、预写日志和日志结构合并树。存储介质变化后,必须知道哪些前提仍然成立,哪些已经失效。

工作原理

HDD。 读取一个块时,磁头先移到对应磁道(寻道通常 5~10ms),再等待目标扇区转到磁头下方(7200rpm 时平均约 4ms)。因此随机读取每秒通常只有数百次,而连续读取、不移动磁头时可达每秒数百 MB。顺序与随机相差百倍以上,这是经典存储设计的出发点。

SSD。 没有活动部件,随机读取以微秒计,但写入并不对称。NAND 闪存按页(数 KB)写入,却只能按块(数 MB)擦除;已写位置不能直接覆盖。控制器会写到新位置、把旧位置标为无效,之后搬移有效页并整块擦除(垃圾回收)。因此设备实际写入量会大于主机请求量,其比率称为写放大(write amplification)。闪存单元还有擦除次数上限,所以控制器通过磨损均衡(wear leveling)平均使用各单元。

NVMe。 SATA 只有一个深度为 32 的命令队列;NVMe 可拥有数万个队列,每个队列也可容纳数万个请求。单次请求延迟未必大幅降低,关键是增加并发请求数(队列深度)才能填满带宽。队列深度为 1 时测出的 IOPS 只能展示设备的一部分能力。

实际工作中的表现

PostgreSQL 的 random_page_cost 默认值 4.0 是按旋转磁盘设定的。在 SSD 或 NVMe 上保持该值,会让优化器把随机访问成本高估四倍,从而低估索引。不少“建了索引却不用”的问题,把它降到约 1.1 就能解决。介质改变后,基于介质的成本模型也必须调整。

仍有一些前提有效:顺序写入在 SSD 上也优于随机写入,只是原因不同。HDD 是因为不用移动磁头,SSD 则是因为能减少垃圾回收和写放大。

用数字建立直觉

用表格看存储设备的差异最清楚,数量级完全不同。

HDD SATA SSD NVMe SSD 内存
随机读取延迟 5~10 ms 0.1 ms 0.02 ms 0.0001 ms
IOPS(随机 4K) 100~200 数万 数十万~百万
顺序带宽 150 MB/s 500 MB/s 3~7 GB/s 50 GB/s+
队列深度 1(实际上) 32 65,536 × 多个队列

HDD 随机 IOPS 只有约 200 的原因是物理运动。磁头移动和盘片旋转一次就要 5~10ms,因此数据库放在 HDD 上时,每秒约 200 次随机查询就是上限。

NVMe 比 SATA SSD 快主要源于接口而不是介质。SATA 只有一个深度 32 的队列,NVMe 则有多个深度 65,536 的队列,每个 CPU 核心都可拥有自己的队列,并行能力截然不同。

区分顺序与随机就是设计

即使是同一设备,不同访问模式的性能也可能相差十倍以上。

第三种情况在实际工作中很常见。若每张缩略图或每段日志都单独存文件,就可能出现磁盘容量尚有剩余但 inode 已耗尽,无法继续写入。可用 df -i 检查。

写入何时真正到达磁盘

应用调用 write() 并不表示数据已经落盘。

앱 버퍼 → 페이지 캐시(커널) → 장치 캐시 → 매체
              ↑ write() 는 여기까지만 보장한다
              ↑ fsync() 가 아래로 밀어낸다

断电时,未经过 fsync 的内容会消失。数据库每次提交都调用 fsync,这也决定了写入性能上限。

这里还有磁盘写缓存的陷阱:如果设备只写入缓存就返回“完成”,连 fsync 都会说谎。服务器级 SSD 用断电保护(PLP)电容解决此问题,这正是消费级 SSD 不适合数据库服务器的原因。

后续测验将确认什么

确认你能区分:介质变化后,哪些设计前提已经失效,哪些仍然成立。