什么是预读
预读(readahead)让内核在应用读取顺序数据时提前把后续数据装入页缓存,减少等待次数,顺序读吞吐因此明显提升。它有两个观察口径:blockdev --getra/--setra 以 512 字节扇区为单位,/sys/block/<dev>/queue/read_ahead_kb 以 KiB 为单位,两者描述同一个值。默认值通常为 128KB,SSD 与顺序读为主的场景可以适当调大,随机读为主则应保持或调小。
基本信息
| 查看(扇区) | blockdev --getra /dev/sda |
|---|---|
| 查看(KiB) | cat /sys/block/sda/queue/read_ahead_kb |
| 设置(扇区) | blockdev --setra 8192 /dev/sda |
| 设置(KiB) | echo 1024 > /sys/block/sda/queue/read_ahead_kb |
| 持久化 | udev 规则或 tuned 配置,重启后不保留 |
典型使用场景
- 大文件顺序读、日志回放、备份恢复:调大预读提升吞吐
- 数据库数据文件全表扫描:顺序占比高时可评估上调
- 随机读为主的 OLTP:预读过大反而浪费带宽与页缓存
- 虚拟机镜像与镜像仓库:读模式以顺序为主,常做统一调优
- 排查读吞吐上不去:先确认预读与 IO 调度器是否被改成非默认值
查看与设置
查看与设置
blockdev --getra /dev/sda # 扇区口径,8192 ≈ 4MiB
cat /sys/block/sda/queue/read_ahead_kb # KiB 口径,与上面对应
lsblk -o NAME,ROTA,SCHED,RA # 一览多块盘的预读值
sudo blockdev --setra 8192 /dev/sda # 调成 4MiB
sudo udevadm control --reload && sudo udevadm trigger # 让 udev 规则重放
# 持久化示例:/etc/udev/rules.d/60-iosched.rules 里 ACTION=="add|change",KERNEL=="sda",ATTR{queue/read_ahead_kb}="1024"取值参考
| 场景 | 建议范围 | 说明 |
|---|---|---|
| 随机读为主(OLTP) | 128KB 左右或更小 | 预读命中率低,大了只是浪费 |
| 顺序读为主(备份/日志) | 1MB - 4MB | 减少 IO 次数,吞吐提升明显 |
| NVMe SSD | 可适度调大 | 设备本身延迟低,收益不如机械盘显著 |
| 机械盘 | 视寻道成本评估 | 过大预读会挤占其他流的带宽 |
两种口径单位不同(扇区 vs KiB),换算前先确认,把 --setra 的值当成 KiB 会差 2 倍。
预读属于缓存与带宽的再分配:给离线任务调大的同时会把在线业务的页缓存挤出去,变更前后都要看命中率与 P99。
两个口径换算
| 扇区口径 | blockdev --getra,单位 512 字节 |
|---|---|
| KiB 口径 | /sys/block/<dev>/queue/read_ahead_kb |
| 换算关系 | KiB 值 = 扇区值 ÷ 2 |
| 一致性 | 改任一边另一边同步变化,可互相校验 |