关于ssd存储原理的介绍

众所周知SSD的读写速度远比hdd磁盘要快,理解ssd的工做原理使咱们开发处高效储存方案。
 linux

linux 相关指令算法

fstrim --fstab --verbose ## 回收(discard)文件系统上对应磁盘未使用的块
blkdiscard /dev/nvme1n1  ## 回收并擦除(discard)整个SSD块设备
wipefs -a /dev/nvme1n1   ## 擦除(erase)文件系统的签名

 

fstrim编程

fstrim命令实际能够视为手动对SSD磁盘下发TRIM指令。使用-v参数能够直接查看TRIM回收擦除空间的大小。fstrim是针对已挂载的文件系统的SSD分区json

root@xxxx:~# fstrim --help

Usage:
 fstrim [options] <mount point>

Discard unused blocks on a mounted filesystem.

Options:
 -a, --all           trim all supported mounted filesystems
 -A, --fstab         trim all supported mounted filesystems from /etc/fstab
 -o, --offset <num>  the offset in bytes to start discarding from
 -l, --length <num>  the number of bytes to discard
 -m, --minimum <num> the minimum extent length to discard
 -v, --verbose       print number of discarded bytes
 -n, --dry-run       does everything, but trim

 -h, --help          display this help
 -V, --version       display version

For more details see fstrim(8).

 

如下是执行后返回的结果,以NVMe 为列ubuntu

/home: 32.5 GiB (313011310592 bytes) trimmed on /dev/mapper/gat204--vg-root
/boot/efi: 102.2 MiB (607301632 bytes) trimmed on /dev/nvme1n1p1
/boot: 732.5 MiB (825778176 bytes) trimmed on /dev/nvme1n1p2
/: 60.7 GiB (65154805760 bytes) trimmed on /dev/mapper/gat204--vg-swap_1

 

ubuntu与debian的systemd 服务能够定时执行fstrim,省去手写crontab脚本工做。缓存

systemctl status fstrim.timer ##查询服务状态
systemctl enable fstrim.timer ##开启定时TRIM功能

 

blkdiscard架构

blkdiscard用于擦除(discard)SSD设备扇区,和fstrim不一样这条命令直接用在块设备上,默认擦除整个块设备的全部扇区。app

root@xxxx:~# blkdiscard -help

Usage:
 blkdiscard [options] <device>

Discard the content of sectors on a device.

Options:
 -o, --offset <num>  offset in bytes to discard from
 -l, --length <num>  length of bytes to discard from the offset
 -p, --step <num>    size of the discard iterations within the offset
 -s, --secure        perform secure discard
 -z, --zeroout       zero-fill rather than discard
 -v, --verbose       print aligned length and offset

 -h, --help          display this help
 -V, --version       display version

For more details see blkdiscard(8).
root@ECSab169d:~# man blkdiscard

 

擦除(discard)成功后,没有返回结果分布式

root@xxxx:~# blkdiscard /dev/nvme1n1
root@xxxx:~#

 

wipefs性能

wipefs是linux自带的程序,用来擦除(erase)文件系统的签名,不会清空文件系统或设备中的任何其余数据。默认状况下, wipefs 不会擦除非整个磁盘设备上的嵌套分区表。为此,须要—force选项。

root@gat204:~# wipefs --help

Usage:
 wipefs [options] <device>

Wipe signatures from a device.

Options:
 -a, --all           wipe all magic strings (BE CAREFUL!)
 -b, --backup        create a signature backup in $HOME
 -f, --force         force erasure
 -i, --noheadings    don't print headings
 -J, --json          use JSON output format
 -n, --no-act        do everything except the actual write() call
 -o, --offset <num>  offset to erase, in bytes
 -O, --output <list> COLUMNS to display (see below)
 -p, --parsable      print out in parsable instead of printable format
 -q, --quiet         suppress output messages
 -t, --types <list>  limit the set of filesystem, RAIDs or partition tables
 -h, --help          display this help
 -V, --version       display version

Available output columns:
     UUID  partition/filesystem UUID
    LABEL  filesystem LABEL
   LENGTH  magic string length
     TYPE  superblok type
   OFFSET  magic string offset
    USAGE  type description
   DEVICE  block device name

For more details see wipefs(8).

 

检查SSD是否支持TRIM

##能够经过 /sys/block 下的信息来判断 SSD 支持 TRIM, discard_granularity 非 0 表示支持。
# cat /sys/block/sda/queue/discard_granularity
0
# cat /sys/block/nvme0n1/queue/discard_granularity
512

 

存储元器件(闪存颗粒类别)

SSD的储存是NAND-Flash闪存颗粒,分为SLC、MLC和QLC四种。能够粗略地把闪存颗粒理解成是一个电容加上电压计的组合。一个电容能存放一个比特的数据,电压计使电容能区分不一样电压,不一样的电压能存放更多的比特数据。


 

SLC(Single-Level Cell): 每一个Cell单元存储1bit信息,也就是只有0、1两种电压变化,结构简单,电压控制也快速,反映出来的特色就是寿命长,性能强,P/E寿命在1万到10万次之间,但缺点就是容量低而成本高.

MLC(Multi-Level Cell): 每一个cell单元存储2bit信息,须要更复杂的电压控制,有00,01,10,11四种变化,这也意味着写入性能、可靠性能下降了。其P/E寿命根据不一样制程在3000-5000次不等.

TLC(Triple-Level Cell):每一个cell单元存储3bit信息,电压从000到001有8种变化,容量比MLC再次增长1/3,成本更低,可是架构更复杂,P/E编程时间长,写入速度慢,P/E寿命也降至1000-3000次,部分状况会更低.寿命短只是相对而言的,一般来说,通过重度测试的TLC颗粒正常使用5年以上是没有问题的.

QLC(Quad-Level Cell):QLC或者能够叫4bit MLC,电压有16种变化,可是容量能增长33%,就是写入性能、P/E寿命与TLC相比会进一步下降。具体的性能测试上,美光有作过实验。读取速度方面,SATA接口中的两者均可以达到540MB/S,QLC表现差在写入速度上,由于其P/E编程时间就比MLC、TLC更长,速度更慢,连续写入速度从520MB/s降至360MB/s,随机性能更是从9500 IOPS降至5000 IOPS,损失将近一半.

这四类当中,SLC的性能最优,价格超高;MLC性可以用,价格适中为消费级SSD应用主流;TLC综合性能最低,价格最便宜,但能够经过高性能主控、主控算法来弥补、提升TLC闪存的性能;QLC出现的时间很早,价格便宜,容量大。

 

P/E以及其SSD底层储存结构

P指的是Program(编程),E指的是Erease (擦除), 闪存彻底擦写一次能够称为1次P/E,所以闪存的寿命以P/E为单位。和HDD机械硬盘不一样,HDD的数据是能够覆写的(Overwrite),而SSD在写入数据前必须先进行擦除(erase),通常在格式化文件系统步骤或者SSD出厂配置的过程当中,SSD已进行了全盘擦除(erase),所以SSD的首次写入数据是直接编程。

SSD 在闪存单元中存取数据时有 pageblock 的概念。SSD 被划分红不少 block, 而 block 被划分红不少 page。

 

NAND-Flash读写流程

Page是NAND-Flash单次读写单位,大小通常为4K或者4K字节的倍数,写操做只能写到空的 page,而清除数据(Erase) 是以 块(block) 为单位的。块的擦除次数有寿命限制,超限制就会变成坏块。

 

用户对SSD的写入数据操做能够分为两种类型

1.原来SSD磁盘上没有数据,写入数据。

2.SSD磁盘上有数据,对该数据进行修改(包括删除)。

前者只需把数据直接写入到空白页便可,后者则是read-modify-write方式操做,读取原有page的内容到缓存中并进行更新,最后写入到其余空的page,原有的page置为无效页。

能够想象对文件的持续反复的修改,将会产生大量的无效页,这就须要“垃圾回收”(Garbage Collection-gc)机制来回收这些无效页,不然能够写入空间愈来愈小。

 

FTL 和磨损均衡

SSD的主控执行磨损均衡(Wear-Leveling)策略,使SSD磁盘各个块的擦除次数均匀分摊到各个块上。就像内存MMU同样,SSD内部使用闪存转换层(FTL)存放了逻辑块地址(Logical Block Address,简称 LBA)到物理块地址(Physical Block Address,简称 PBA)的映射。操做系统访问的硬盘地址,其实都是逻辑地址。只有经过 FTL 转换以后,才会变成实际的物理地址,找到对应的块进行访问。操做系统自己,不须要去考虑块的磨损程度,只要和操做机械硬盘同样来读写数据就行了。

 

“垃圾回收”机制

写入放大(write amplification)

上文说起过数据的反复修改会产生大量的无效页,一旦整个块(block)的空间不足以写入数据,SSD会将这个块(block)的数据读入到缓存中,擦除这个块(block)所中的页,而后再把缓存中已更新的数据写入进去。这种read-erase-modify-write过程,就比如写入的数据可能只有一个页4KB,但实际要擦除而且写N个页,称之为写入放大。

写入放大的倍数越大,写入的速度就越慢。

 

TRIM指令
TRIM是SSD的ATA-8指令,解决写入放大的关键。

文件系统在修改或者删除过程当中,发送给通知给SSD记录产生的无效页,间隔必定时间再统一回收擦除全部无效页,擦除更新无效页所在的块(block)。

一方面预留足够多的空间,避免因空间不足产生写入放大的状况。另外一方面,使用TRIM,在IO闲时回收擦除无效页,这样有效保证SSD的性能以及提升寿命。

 

discard与TRIM的区别

在linux术语中,discard指的就是TRIM

 

不建议使用linux系统默认的TRIM功能

TRIM功能有两种方式启动,一种是连续TRIM,就是直接在文件系统回收块的时候直接发TRIM命令,这种方式对性能影响比较大,在fstab挂载的时候把default修改为discard。另一种是按期执行fstrim批量进行TRIM操做,这样避免平时的性能影响,不过fstrim的执行时机要选好,毕竟批量TRIM的时候会对其它任务性能影响较大。

根据文章《Ubuntu Doesn’t TRIM SSDs By Default: Why Not and How To Enable It Yourself》说起到

“The kernel implementation of realtime trim in 11.2, 11.3, and 11.4 is not optimized. The spec. calls for trim supporting a vectorized list of trim ranges, but as of kernel 3.0 trim is only invoked by the kernel with a single discard / trim range and with current mid 2011 SSDs this has proven to cause a performance degradation instead of a performance increase. There are few reasons to use the kernels realtime discard support with pre-3.1 kernels. It is not known when the kernels discard functionality will be optimized to work beneficially with current generation SSDs.” [Source]

利用内核方式的discard 方式没法感知对SSD当前性能的影响。

 

实践

使用fio测试nvme裸设备

使用fio对裸设备直接进行randwrite测试,在超过30分钟速度由400MiB/s下降至80MiB/s 分析缘由得出SSD触发了放大写现象,而且因为没有挂载文件系统,没法使用fstrim手动回收空间(能够理解成,在没有文件系统标记下,SSD也不知道哪些是无效页),再次进行fio测试速度依然是80MiB/s。使用blkdiscard进行全盘擦除后,速度恢复正常。

参考文献

《Trim命令》 wiki百科

《浅谈分布式存储之SSD基本原理》滴滴云

《Linux 下启用 SSD TRIM 功能》Louis

 

结束语

当使用fio直接ssd磁盘进行写入测试后,对磁盘使用blkdiscard可恢复原来的速度。