🐧 第八章 外部存储器
📄 一句话概括

闪存的一个页写完就不能再改,要改必须擦掉整块(256 KB,64 个页)。所以改 1 个页最坏要搬 64 个页。1 GB 数据:顺序写只写 1.0 GB,4 KB 随机写(盘快满)要写 4.0 GB——同一块盘寿命差 4 倍。

📝 本节和前面几节的关系

8.1 到 8.10 讲的全是机械盘,这一节换介质:SSD 没有机械臂,所以 8.1 的那些结论全要重写。但它有自己的一套限制,而且更隐蔽。

一、闪存的三个单位

页(page):4 KB,读和写的最小单位。关键限制:一个页写完就不能再改。 块(block):256 KB,擦除的最小单位。改一个页,要把整块擦掉。 整盘:几百 GB,由几万个块组成。 为什么要这么设计?因为闪存是靠【注入电子】记数据的,把电子打进去容易,单独抽出来难——只能整块一起抽,这就是【擦除】。所以【写】和【擦】是两个不同粒度的操作。 这个不对称是全部分析的起点。它导致了一个很反直觉的结论:SSD 上【覆盖写】比【追加写】贵得多。

二、改 1 个页 = 搬 64 个页

改一个已经写过的 4 KB 页,实际要做三件事: ① 把那个块里【还有效的页】读出来(4 KB × 若干); ② 擦掉整块(256 KB); ③ 把有效页 + 新页写回去。 最坏情况:块是满的,改 1 页就要搬 64 页——写放大 64 倍。 实际上没这么惨,因为 FTL(闪存转换层)会挑【垃圾多的块】来擦,而且它会把逻辑地址映射到新的物理页,把原来那页标记成无效,等以后再回收。这叫【写时重定向】。所以真实写放大通常在 2 到 4 倍。 注意这个设计思路:既然不能原地改,那就【写到别处去】,和 7.6 讲的写时复制是同一个想法。只不过文件系统是为了崩溃一致性,SSD 是为了物理限制。

三、1 GB 数据的四种写法

Demo 88 算了四种写法:顺序写(一次写满整块)放大 1.0 倍;大块随机写(128 KB)1.5 倍;4 KB 随机写(轻负载)2.0 倍;4 KB 随机写(盘快满)4.0 倍。 所以 1 GB 有效数据,实际写进闪存的是 1.0 到 4.0 GB。 换成寿命:一块标称 600 TBW 的盘(总写入量 600 TB):全按 4 KB 随机写,能写进去的有效数据只有 150 TB;全按顺序写,能写 600 TB。 同一个盘,寿命差 4 倍。这就是【SSD 不适合当数据库重写盘】这个说法的来历。不过现代企业级 SSD 的 DWPD 参数已经把这件事设计进去了——数据中心盘的 DWPD 通常是 1 到 3,消费级只有 0.3 左右。 对日常使用者的实际建议:别把 SSD 当临时工作盘反复覆盖大文件,日志、编译缓存、虚拟机镜像都是高写入场景。

四、TRIM 与三层单元

TRIM:文件被删时,文件系统告诉 SSD【这些页不用保留了】。没有它,SSD 不知道那是垃圾,将来搬块时还会把垃圾一起搬——放大倍数就上去了。所以 TRIM 不只是【清理】,它是【保护寿命】的。 TLC/QLC:一个单元存 3 位/4 位。容量大、便宜,但写入更慢、寿命更短。所以大容量消费级 SSD 的持续写入速度会在缓存写满后掉下来——因为 SLC 缓存用完了,得直接往 TLC/QLC 里写。 这也是【SSD 标称速度】要看清楚的原因:厂商宣传的那个数通常是【SLC 缓存内】的速度,持续写几百 GB 之后会掉到几分之一。 最后一句对比:机械盘的性能是【恒定的】,SSD 的性能是【依赖状态的】。空盘、半满、快满,速度完全不一样。所以测 SSD 一定要写明【盘用了多少】。

五、动手 Demo:SSD——为什么随机写比顺序写伤盘

按闪存的物理限制算一遍:改一个页要搬多少页,写放大是多少,一块 600 TBW 的盘能用多久。

BLOCK, PAGE = 256 * 1024, 4 * 1024
pages_per_block = BLOCK // PAGE
print("一块 %d KB,一页 %d KB,一块 %d 页"
      % (BLOCK // 1024, PAGE // 1024, pages_per_block))
print("最坏写放大 = %d 倍" % pages_per_block)

TOT = 1.0        # GB 有效数据
cases = (("顺序写", 1.0), ("大块随机 128 KB", 1.5),
         ("4 KB 随机 轻负载", 2.0), ("4 KB 随机 盘快满", 4.0))
for name, wa in cases:
    print("%-18s 放大 %.1f 倍  实际写 %.1f GB" % (name, wa, TOT * wa))

TBW = 600
print("600 TBW 的盘:顺序写可用 %.0f TB,4 倍放大只剩 %.0f TB"
      % (TBW / 1.0, TBW / 4.0))

实跑输出:

--------------------------------------------------------------------
SSD——为什么随机写比顺序写伤盘
--------------------------------------------------------------------
① 闪存的三个单位

  单位            典型大小     能做什么
  -----------------------------------------------------
  页(page)      4 KB         读、写;写只能写一次
  块(block)     256 KB       擦除的最小单位
  整盘            几百 GB      由几万个块组成

  **关键限制**:**一个页写完就不能再改,要改必须【先擦掉整块】。**
  **擦一块是 256 KB,相当于 64 个页。**

② 于是【改 1 个页】变成了【搬 64 个页】

  **改一个已经写过的 4 KB 页**,实际要做的事:
  **① 把那个块里【还有效的页】读出来(4 KB × 若干);**
  **② 擦掉整块(256 KB);**
  **③ 把有效页 + 新页写回去(4 KB × 若干 + 1)。**

  **最坏情况**:**块是满的,改 1 页就要搬 64 页——写放大 64 倍。**
  **实际因为 FTL 会挑【垃圾多的块】来擦,写放大通常在 2~4 倍。**

③ 算一遍:1 GB 数据两种写法

  写法                       写放大     1 GB 实际写进闪存
  -----------------------------------------------------------
  顺序写(一次写满整块)     1.0 倍     1.0 GB
  大块随机写(128 KB)       1.5 倍     1.5 GB
  4 KB 随机写(轻负载)      2.0 倍     2.0 GB
  4 KB 随机写(盘快满)      4.0 倍     4.0 GB

  **一块标称 600 TBW 的盘**(总写入寿命 600 TB):
  **全按 4 KB 随机写(放大 4 倍)**,**能写进去的有效数据只有 150 TB。**
  **全按顺序写(放大 1 倍)**,**能写 600 TB。**

  **所以同一个盘,用法不同,寿命差 4 倍。**
  **这也是【SSD 不适合当数据库的重写盘】这个说法的来历**——
  **不过现代企业级 SSD 的 DWPD 已经把这件事设计进去了。**

④ TRIM 与三层单元

  **TRIM**:**文件被删时告诉 SSD【这些页不用保留了】**。
  **没有它,SSD 不知道那是垃圾,将来搬块时还会把垃圾一起搬——放大倍数就上去了。**
  **TLC/QLC**:**一个单元存 3 位/4 位**,
  **容量大、便宜,但写入更慢、寿命更短。**
  **所以大容量消费级 SSD 的持续写入速度会在缓存写满后掉下来。**

  📋 **Linux 上查看与开启 TRIM**:`sudo fstrim -v /`(手动);
  `systemctl status fstrim.timer`(定期);
  `lsblk -D` 看盘是不是支持 `discard`。

最坏 64 倍是一个上界,真实值由 FTL 的垃圾回收策略决定,通常在 2 到 4 倍。所以下面那张表用的是 1.5、2.0、4.0。 注意【盘快满】那一行放大最高:因为盘满的时候没有空闲块可以周转,每次写都要先回收,回收时垃圾又少,搬的页就多。所以 SSD 要保持一定空闲空间(一般建议留 20%)。 600 TBW 换成【每天写多少年】:每天写 100 GB 顺序数据,能用 16 年;同样的量换成 4 KB 随机写,只剩 4 年。

📋 Linux 上查看与开启 TRIM:sudo fstrim -v /(手动); 📋 systemctl status fstrim.timer(定期);lsblk -D 看盘是不是支持 discard。

30 秒实验

  1. 算一遍:如果你每天写 50 GB,一块 600 TBW 的盘在 4 倍放大下能用几年?
  2. lsblk -D,看你的盘支持不支持 discard。
  3. 查一下:cat /sys/block/nvme0n1/queue/rotational,0 表示固态。

常见误区

  1. 【SSD 没有机械部件,所以不会有性能退化】。盘越满、写入越随机,性能掉得越明显——因为回收要搬更多有效页。
  2. 【写放大只影响寿命,不影响速度】。回收本身要花时间,所以写放大高的时候,写入速度也会掉。
  3. 【TRIM 只是清理垃圾,可以不开】。不开 TRIM,SSD 不知道哪些页是垃圾,搬块时会连垃圾一起搬,写放大变高、寿命变短。
自测三问(点开对答案) 1. 为什么改一个 4 KB 的页,最坏要搬 64 个页? —— **因为擦除的最小单位是块(256 KB = 64 页)**,**而一个页写完不能单独改。****要改就得把整块的有效页读出来、擦掉、再写回。** 2. 为什么 4 KB 随机写的寿命只有顺序写的四分之一? —— **因为随机写会频繁触发块回收**,**每次回收都要搬运块里剩下的有效页,写放大升到 4 倍。****同样的有效数据,实际写进闪存的量变成 4 倍。** 3. TRIM 为什么能延长寿命? —— **它告诉 SSD 哪些页已经作废**,**回收时就不必搬运它们。****没有 TRIM,SSD 会把垃圾当有效数据一起搬,写放大变高。**

相关笔记