固态硬盘(Solid State Drive)用固态电子存储芯片阵列而制成的硬盘,由控制单元和存储单元(FLASH 芯片、DRAM 芯片)组成。固态硬盘 I/O 性能相对于传统硬盘大大提升。并且使用时也没有传统硬盘那种噪声。现在的个人电脑基本都会用固态硬盘作为系统盘。不过固态硬盘有擦写次数限定,使用寿命会有所限制。本文介绍使用 linux 操作系统时如何优化固态硬盘的性能,并延长固态硬盘的使用寿命。

开启 Trim

为了解决硬盘降速的问题,微软联合各大 SSD 厂商开发了一个新技术—— Trim 。Trim 指令也叫 disable delete notify(禁用删除通知),属于 ata8-acs2 规范的技术指令。使用 SSD 时必须确保开启系统中 Trim 指令。

系统对支持 Trim 指令的 SSD 启动 Trim 命令后,这时在对 SSD 进行数据删除的操作,硬盘不会急于执行擦除操作,而是等到再次有写入操作的时候再执行,因为这时相关区域已经可以重新使用了,就不用花时间去擦除原本的数据。其速度比直接读写硬盘去标记删除区域要快得多,既提升了读写效率又大大减轻了固态硬盘的损耗。

如果 SSD 支持 Trim 指令,那么 SSD 就可以长期使用不掉速,否则 SSD 会随着使用时间越长速度就越慢。

linux 对 Trim 的支持

在 linux 3.8 后,各种文件系统对 Trim 的支持,开始不断添加到内核中。目前各文件系统对 Trim 的支持如下:

文件系统 持续 TRIM(discard 选项) 周期 TRIM (fstrim)
Btrfs Yes Yes
Ext3 No ?
Ext4 Yes Yes
F2FS Yes Yes
JFS Yes Yes
NILFS2 Yes Yes
NTFS-3G No Yes
VFAT Yes Yes
XFS Yes Yes

通过下面这个命令可以验证是否支持 Trim。

1
$ lsblk --discard

查看 DISC-GRAN(丢弃粒度)和 DISC-MAX(丢弃最大字节)列的值。非零值表示 Trim 支持。

开启周期 Trim

util-linux 包提供了 fstrim.servicefstrim.timer systemd 的 unit 文件。 启用 fstrim.timer 将每周激活这个服务,对设备上所有已挂载的支持 discard 操作的文件系统来执行 fstrim。

要查询 Uint 的活动和状态,请参阅 journalctl。要更改计时器或命令运行的周期,请编辑 fstrim.timer systemd 的 unit 文件。

开启持续性 Trim

如果定期运行 fstrim,则无需启用持续 Trim。只需要开启周期 Trim 或持续 Trim 中的一个。

目前 linux 社区大都推荐使用周期 Trim。

/etc/fstab 里使用 discard 参数以启用持续 Trim。

例如:

1
2
/dev/sda1  /       ext4   defaults,noatime,discard   0  1
/dev/sda2 /home ext4 defaults,noatime,discard 0 2

I/O调度器

尽管某些早期算法现已停用,但正式的Linux内核支持许多 I/O 调度程序,这些程序可分为两类:

  1. 多队列调度器
    • none,不应用任何排队算法。
    • mq-deadline,将 deadline 调度程序改编为多线程。
    • Kyber
    • BFQ
  2. 单队列调度器
    • NOOP
    • deadline
    • CFQ

单队列调度器在 linux 5.0 中被移除了。

查看 /sys/block/sdX/queue/scheduler 的内容来检查:

将 sdX 替换为你的硬盘。

1
2
$ cat /sys/block/sda/queue/scheduler
mq-deadline kyber [bfq] none

当前使用的调度器是可用调度器中括号括起来的那一个。

可以自动执行更改 I/O 调度程序的过程,并且该过程在重新引导后仍然有效。例如,以下 udev 规则将 NVMe 的调度程序设置为none,将 SSD/eMMC的调度程序设置为 mq-deadline,将传统驱动器的调度程序设置为 bfq:

创建文件 /etc/udev/rules.d/60-ioschedulers.rules

1
2
3
4
5
6
# set scheduler for NVMe
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/scheduler}="none"
# set scheduler for SSD and eMMC
ACTION=="add|change", KERNEL=="sd[a-z]|mmcblk[0-9]*", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
# set scheduler for rotating disks
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"

最小化硬盘读写的技巧

减少磁盘的读写无疑会增加磁盘的寿命。

atime 参数

使用 noatime, nodiratimerelatime 可以提升 ext2, ext3 及 ext4 格式磁盘的性能。 Linux 在默认情况下使用 atime 选项,每次在磁盘上读取(或写入)数据时都会产生一个记录。这是为服务器设计的,在桌面使用中意义不大。默认的 atime 选项最大的问题在于即使从页面缓存读取文件(从内存而不是磁盘读取),也会产生磁盘写操作!

使用 noatime 选项阻止了读文件时的写操作。大部分应用程序都能很好工作。只有少数程序如 Mutt 需要这些信息。Mutt 的用户应该使用 relatime 选项。使用 relatime 选项后,只有文件被修改时才会产生文件访问时间写操作。nodiratime 选项仅对目录禁用了文件访问时间。relatime 是比较好的折衷,Mutt 等程序还能工作,但是仍然能够通过减少访问时间更新提升系统性能。

注意: noatime 已经包含了 nodiratime。不需要同时指定。

tmpfs

tmpfs 是一个临时文件系统,驻留于你的交换分区或是内存中(取决于你的使用情况)。使用它可以提高文件访问速度,并能保证重启时会自动清除这些文件。

经常使用 tmpfs 的目录有 /tmp, /var/lock 和 /var/run.

大多数 linux 发行版已经自动将必要的文件夹挂载到了内存。不需要你手动设置。

不过如果你有特殊需求,你可以将你的文件夹挂载到内存,从而减少硬盘的读写。注意,这个文件夹的内容每次重启后都会被删除。

例如将 /www/cache 放到内存,只需要编辑 /etc/fstab 加入以下行:

1
tmpfs   /www/cache    tmpfs  rw,size=1G,nr_inodes=5k,noexec,nodev,nosuid,uid=user,gid=group,mode=1700 0 0

如果你经常编译程序,可以将你的编译文件夹放到内存里面。

关闭日志

关闭文件系统日志可以减小硬盘的读写。

可以在格式化时禁用日志。

修改 /etc/mke2fs.conf ,里面的ext4,去掉has_journal 。然后再格式化分区。该分区将不会有日志支持

也可以使用以下命令禁用日志:

1
# tune2fs -O "^has_journal" /dev/sdXN

该命令需要在分区未挂载的时候使用。

禁用日志后非常将容易因为断电而丢失文件。

以上就是我提供的优化 SSD 的技巧了。希望对你有所帮助。