预读参数 readahead

预读让顺序读提前加载数据;两种口径:blockdev --setra(512B 扇区)与 /sys/block/<dev>/queue/read_ahead_kb(KiB)。

什么是预读

预读(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
一致性改任一边另一边同步变化,可互相校验

易错点

  • 随机读为主的负载预读过大反而浪费带宽与缓存,甚至拉高在线业务的读延迟
  • 两种口径单位不同(扇区 vs KiB),换算前先确认,写错单位会得到差 2 倍的值
  • blockdev 与 sysfs 的设置都不持久,重启后回到默认或被 udev/tuned 覆写,必须落到 udev 规则或配置管理里
  • 改完不验证命中率与延迟直接下结论,容易把噪声当成收益;至少做一次同负载的前后对比

数据来源与参考

  • util-linux 文档 blockdev(8)
  • Linux 内核 Documentation/admin-guide/blockdev/
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌