磁盘I/O优化:选SSD、调文件系统、开TRIM、配预读
磁盘I/O往往是启动流程里最慢的一环,没有之一。我见过不少系统,CPU和内存都在「等磁盘」,启动时间硬生生被拖长几十秒。说白了,只要把磁盘I/O这条路铺平了,启动速度的提升几乎是立竿见影的。
这章我们聊四个核心动作:选对SSD、调好文件系统、打开TRIM、配准预读。我自己的习惯是按这个顺序来排查,少走很多弯路。
SSD选型——启动性能的基石
为什么把SSD放在第一位?你想想看,哪怕CPU再快、内存再大,如果磁盘跟不上,启动就是在「等I/O」。我帮一家公司调过一批工控机,原来用的机械硬盘,从按下电源到进桌面要45秒。换成NVMe SSD之后,直接压到12秒。硬件上的差距,软件很难追回来。
选SSD时有几个要点:
- 接口优先选NVMe——NVMe的4K随机读写性能是SATA SSD的3~5倍,启动时大量小文件读取,NVMe优势巨大。
- 容量留余量——SSD剩余空间少于20%时,写入放大效应加剧,性能会明显下滑。我建议至少留30%空余。
- 关注TBW(总写入字节数)——启动场景虽然读多写少,但系统日志、临时文件也会有持续写入,选TBW高的型号更放心。
文件系统选型与调优——ext4、xfs、btrfs怎么选?
文件系统对启动性能的影响,很多人会忽略。其实挂载参数和碎片程度都会直接影响文件读取速度。我见过一个项目,用btrfs没关CoW(写时复制),启动时大量元数据操作导致延迟翻倍。
下面这张表是我个人在实践中总结的对比:
| 文件系统 | 启动场景优势 | 潜在问题 | 我的建议 |
|---|---|---|---|
| ext4 | 成熟稳定,碎片少,挂载快 | 单个目录下文件过多时性能下降 | 保守之选,大部分场景够用 |
| xfs | 大文件读写强,并发好 | 小文件元数据开销略高,删除慢 | 适合/var或数据分区 |
| btrfs | 支持压缩、快照、校验 | CoW可能引入额外延迟,需调参 | 适合有快照需求的场景,但启动分区慎用 |
说几个具体调优动作:
- 挂载参数加 noatime——每次读文件不更新访问时间,减少一次元数据写。这个对启动加速非常直接。
- ext4 关闭日志(仅限启动分区)——如果系统分区是ext4且不担心意外断电,可以用
nobarrier和data=writeback。嗯,这个要谨慎,生产环境别乱来。 - btrfs 关闭 CoW——对
/var/log这类频繁写入的目录,用chattr +C禁用写时复制。
# ext4 挂载示例(优化启动)
/dev/nvme0n1p2 / ext4 defaults,noatime,nodelalloc 0 1
# btrfs 挂载示例(关闭 CoW)
/dev/nvme0n1p2 / btrfs defaults,noatime,compress=zstd 0 1
# 对特定目录关闭 CoW
chattr +C /var/log
/etc/fstab。我曾经在客户机器上改错了参数导致无法启动,只能用救援模式修复,耽误了不少时间。
TRIM——让SSD保持巅峰状态
TRIM是干啥的?说白了,就是告诉SSD哪些数据块已经没用了,可以提前擦除。这样新数据写入时就不需要先擦再写,速度自然快。
我遇到过一台笔记本,用了半年后启动越来越慢,跑分也掉得厉害。一查,TRIM压根没开。开启之后跑了两次fstrim,性能恢复了八成。所以TRIM这件事,一定要检查。
检查TRIM是否启用:
# 查看系统d服务状态
systemctl status fstrim.timer
# 手动执行一次TRIM
fstrim -v /
如果 fstrim.timer 没开,可以手动启用:
systemctl enable fstrim.timer --now
对于持续TRIM(实时通知SSD),可以挂载时加 discard 参数。但要注意,频繁的discard会增加SSD的写入量。我个人习惯是:桌面和服务器用定时TRIM(每周一次),轻载环境可以用discard。
# fstab 中启用 discard
/dev/nvme0n1p2 / ext4 defaults,noatime,discard 0 1
fstrim -v / 后,如果返回了回收的字节数(比如 "50 GiB"),说明TRIM正常工作。如果返回0,可能是SSD不支持或驱动问题。
预读优化——加速数据加载
预读(read_ahead)是内核在读取文件时,提前多读一些数据到内存。启动时大量文件是顺序读取的,预读设得太小会导致频繁I/O,设得太大又浪费内存。
查看当前预读值:
# 查看某个磁盘的预读值(单位为512字节扇区)
blockdev --getra /dev/nvme0n1
# 输出示例:256(即128KB)
调整预读值:
# 设置为2048扇区(即1MB)
blockdev --setra 2048 /dev/nvme0n1
# 如果想持久化,写到 /etc/udev/rules.d/ 中
echo 'ACTION=="add", KERNEL=="nvme[0-9]*", ATTR{bdi/read_ahead_kb}="1024"' \
> /etc/udev/rules.d/60-readahead.rules
启动场景我推荐 1024KB(1MB) 作为起点。NVMe SSD的延迟很低,预读1MB不会浪费太多内存,但能显著减少I/O次数。如果内存紧张(比如4GB以下),可以降到512KB。
我的调优记录: 在一台16GB内存的笔记本上,把预读从128KB调到1024KB后,内核启动阶段读取vmlinuz和initramfs的时间从0.8秒降到了0.5秒。别小看这0.3秒,启动过程中类似的小加速累积起来就很可观了。
调整后可以用 iostat 观察读写请求的变化:
# 安装 sysstat 后
iostat -x 1 /dev/nvme0n1
# 关注 rkB/s 和 r_await,预读增大后 r_await 应该下降
说到底,磁盘I/O优化的四个动作——选SSD、调文件系统、开TRIM、配预读——是一套组合拳。单做其中一项也能看到效果,但四个都做到位了,启动性能才能真正拉满。我经手的项目里,落实了这四项的系统,启动时间普遍缩短了30%~50%。
```