SSD

固态硬盘SSD(Solid State Drive)

闪存组织

  1. 闪存(Flash Memory)
    • 1984:NOR flash
    • 1987:NAND flash
    • 1992:SSD
  2. NOR flash vs NAND flash
    • NOR是字节寻址,NAND是页寻址
    • NOR读延迟比NAND低100x
    • NOR擦除时间比NAND高300x
    • NOR用于取代ROM,存可执行代码
    • NAND用于大量持久化存储设备
  3. 信息存储方式
    • SLC:1 bit/cell 2个值 0/1
    • MLC:2 bit/cell 4个值 00/01/10/11
    • TLC:3 bit/cell 8个值
    • QLC:4 bit/cell 16个值

NAND闪存组织

  1. Flash package
    • 多个 die
  2. Die
    • 多个 Plane/Bank
  3. Plane/Bank
    • 很多块(擦除块)
    • 一些寄存器
  4. 块(Block/Erase Block)
    • 很多页
  5. 页(Page)
    • 由数据区与OOB(Out of Band)区构成
    • 数据区用于存储实际数据
    • OOB区用于记录
      • ECC
      • 状态信息:Erased/Valid/Invalid
      • Logic Page Number
    • 页大小
      • SLC通常为2KB8KB,TLC通常为4KB16KB
    • 块大小
      • SLC通常为128KB、256KB...
      • TLC通常为2MB、4MB...

闪存的操作接口

  1. 读:Read a page
    • 读的粒度是页
    • 读很快,读延迟在几十微秒
    • 读延迟与位置无关,也与上一次读的位置无关(和磁盘不同)
  2. 擦除:Erase a block
    • 把整个块写成全1
    • 擦除的粒度是块,必须整块擦除
    • 很慢:擦除时间为几个毫秒
    • 需软件把块内有效数据拷贝到其它地方
  3. 写:Program a page
    • 擦除后才能写,因为写只能把1变成0
    • 写的粒度是页
    • 写比读慢,比擦除快,写延迟在几百微秒

页的状态

  1. 初始状态为Invalid
  2. 读时,不改变页的状态
  3. 擦除时,块内所有页的状态变为Erased
  4. 写时,只能写状态为Erased的页,写后页状态变为Valid

闪存的性能和可靠性

  1. 性能
    • 写延迟比读高10倍以上
    • 写延迟波动幅度大
    • 擦除很慢:约为磁盘定位延迟
    • 延迟随密度增加而增长
  2. 可靠性
    • 磨损:擦写次数有上限,随密度增加而减少
    • 干扰:读写一个页,相邻页中一些位的值发生翻转
  3. 闪存特性
    • 读延迟很低:随机读的性能远优于磁盘
    • 写慢:必须先擦除再写,约为磁盘写(ms级)
    • 磨损:每个块擦写次数有上限

基于闪存的SSD

  1. 用很多闪存芯片来构成一个持久化存储设备SSD
  2. 多个闪存芯片:并行I/O,提高I/O性能
  3. 与主机的接口:提供标准块设备接口
  4. 数据缓存和缓冲:SRAM/DRAM
  5. 闪存控制器(硬件)和FTL(固件):控制逻辑
    • 主机命令转换成闪存命令(Read/Erase/Program)
    • 逻辑块地址转换成闪存的物理地址(页/块)
    • 缓存替换

FTL

最简单的FTL:直接映射

  1. Direct Mapping
    • 逻辑块的第N块直接映射到物理的第N页(假设逻辑块与物理页都为4KB)
  2. 读操作容易:读逻辑第k页
    • 读物理第k页
  3. 写操作麻烦:写逻辑第k页
    • 第k页所在闪存块(记为B0)
    • 把B0整个块读出来
    • 把B0整个块擦除
    • B0中的旧页和新的第k页:以顺序方式一页一页再写入B0
  4. 缺陷:写性能极差
    • 每写一个页,要读整个块、擦除整个块、写整个块
    • 写放大

FTL改进:异地更新

  1. 核心思想:异地更新(out-of-place update)
    • 不再执行原地更新
    • 每次写页,写到一个新位置(新的物理页地址)
  2. 页级映射
    • 页级映射表:LPN -> 物理页地址PPN
      • 整个放在内存中
      • 持久化:利用页的OOB区来保存映射表
      • 随着写页而被写到闪存
      • 掉电或重启,扫描OOB区来恢复映射表
    • 优点:
      • 性能好:减少写放大
      • 可靠性好:映射关系被自动写入闪存
    • 问题:
      • 重写产生垃圾页
        • 每次写到新位置,导致原先页的内容无效
      • 内存开销大
        • 映射表全部放内存
        • 映射表的大小与SSD容量成正比
  3. 写一个逻辑页k
    • 寻找一个空闲页p(例如当前擦除块中下一个空闲页p)
    • 在映射表中记录:逻辑页k -> 物理页p
  4. 读一个逻辑页k
    • 查映射表,获得逻辑页k对应的物理页地址p
    • 读物理页p

垃圾回收

  1. 思想
    • 选择一个含垃圾页的块
    • 把其中的有效页拷贝到其他块中(先读再重写)
    • 回收整个块,并把它擦除
  2. 如何判断有效页?
    • 每个物理页记录它对应的逻辑页地址(OOB区)
    • 查映射表,如果映射表记录的 PPN=该页,是有效页
  3. 问题:开销非常大
    • 有效页需要拷贝:先读再重写
    • 开销与有效页所占的比例成正比
  4. 解决办法:超配(over-provisioning)
    • 实际物理空间比用户所见空间更大:多15%~45%
      • 例如,用户看到100GB的SSD,实际上内部是120GB
      • GC时将数据写入 over-provisioning space,减少对性能的影响
    • GC一般在SSD后台执行,尽量再设备不忙时执行,但是受限于空闲页的数量
      • 空闲页不足的时候,即使设备忙也需要开始执行GC

块级映射(Block-Level Mapping)

  1. 块级映射
    • 逻辑地址空间划分为chunk,chunk size = 擦除块(物理块)size
    • 映射表:chunk# -> 擦除块(物理块)地址 PBN
  2. 读一个逻辑页
    • 逻辑页地址 = chunk# || 偏移
    • 用chunk#查映射表,获得相应的擦除块地址PBN
    • 物理页地址 = PBN || 偏移
  3. 问题:小规模写性能差
    • 写粒度小于擦除块:拷贝有效页(读 & 写),导致写放大
    • 小写很常见:擦除块通常较大(大于256KB)

混合映射(Hybrid Mapping)

  1. 思想
    • 将擦除块(物理块)划分为两类:数据块和日志块
    • 写逻辑页时都写入日志块
    • 数据块采用块级映射,数据映射表
    • 日志块采用页级映射,日志映射表
    • 适当的时候把日志块合并为数据块
  2. 读一个逻辑页
    • 先查日志映射表,按页级映射的方法
    • 如果没找到,再查数据映射表,按块级映射的方法

合并方式

  1. Switch Merge
    • 直接把日志块转成数据块:前提是整个日志块的页序与原数据块中的页序一致
    • 把原来的数据块回收擦除
    • 优点:开销低,只修改映射表信息,无数据拷贝
  2. Partial Merge
    • 把数据块中有效页拷贝到日志块:日志块中页序与原数据块中的页序一致
    • 把日志块转成数据块,把原来的数据块回收擦除
    • 有数据拷贝开销
  3. Full Merge
    • 分配一个新的日志块,从数据块和日志块分别拷贝有效页到新日志块
    • 把新日志块转成数据块
    • 把原来的数据块和日志块都回收擦除
    • 开销很大:需要拷贝整个物理块的数据(读 & 写)

磨损均衡

  1. 目标
    • 让所有块被擦除的次数近似
  2. 动态磨损均衡
    • 每次写时,选择擦除次数较少或最少的空闲块
    • 局限性:不同数据的修改频率不同
      • 例子:只写一次的数据(static data),很少写的数据(cold data)
  3. 静态磨损均衡
    • 动态磨损均衡不考虑不会被回收的物理块,例如长时间不被修改的物理块(写冷块)
    • 不再被写,不再有磨损
    • 解决办法:FTL定期重写冷块,将其写入磨损较多的块

总结

  1. SSD FTL的主要功能
    • 地址映射
    • 垃圾回收
    • 磨损均衡
    • 请求调度
    • 缓存管理
    • 坏块管理