nr_requests 队列深度

每设备允许排队的请求数上限;调大提升突发吞吐但抬高峰值延迟,NVMe 默认往往已较大。

什么是 nr_requests

nr_requests 是块层为每块设备设置的排队请求上限:内核把来自不同进程的 IO 合并排序后放入该设备的请求队列,队列满后新的提交会被背压阻塞或走旁路。它属于上层队列深度,与设备本身的硬件队列深度(NVMe 的 queue_depth、SAS 的 tag 数)是两层概念:上层调大只让更多请求在场排队,并不能让设备本身变快,反而通常抬高单次 IO 的尾延迟。

基本信息

路径/sys/block/<dev>/queue/nr_requests
典型默认SATA/SAS 常为 64 或 128,NVMe 常为 1024
调大影响突发吞吐上升,平均与尾延迟通常上升
相关项queue/scheduler、queue/nr_requests、device/queue_depth
持久化udev 规则或 tuned,重启后不保留

典型使用场景

  • 顺序写为主的备份与归档:适当调大让 IO 队列填满,提升设备利用率
  • 延迟敏感服务调参后出现 P99 恶化:先看是不是有人调大了队列深度
  • 排查 IO 提交被阻塞:结合队列长度判断是设备慢还是上层次数过多
  • 虚拟化宿主:给虚拟机磁盘评估队列深度,避免单个虚机抢占
  • 存储阵列与 NVMe 上线时的基线核对:确认参数与厂商建议一致

查看与调整

查看与调整
cat /sys/block/sda/queue/nr_requests        # 当前上限
cat /sys/block/sda/queue/scheduler          # 顺带确认调度器
cat /sys/block/sda/device/queue_depth       # 设备侧硬件深度
lsblk -o NAME,ROTA,SCHED,RA                  # 多设备一览
sudo sh -c 'echo 128 > /sys/block/sda/queue/nr_requests'   # 调整
# 持久化示例(udev):ACTION=="add|change", KERNEL=="sda", ATTR{queue/nr_requests}="128"
iostat -x 1 5 | grep -w sda                 # 用 aqu-sz/await 验证前后差异

相关指标与判读

指标含义异常信号
aqu-sz平均队列长度(iostat -x)长期贴着 nr_requests 说明队列经常排队
await平均 IO 完成时间(ms)调大队列后明显上升说明在牺牲延迟换吞吐
queue_depth设备硬件并发能力上层值远超它只会堆排队
%util设备忙闲比例接近 100% 提示设备已饱和,调参无效
多路径与 LVM 场景要区分调哪一层:dm-* 设备的队列与底层物理盘的队列各自独立,只改上层通常起不到预期效果。
队列深度与 IO 调度器(mq-deadline、none、bfq)共同决定行为,改之前先记录 iostat 基线,避免把配置变化当成设备改善。

易错点

  • 与设备固有队列深度是两层概念,上层调大不等于设备更快,只是更多请求堆在队列里
  • 延迟敏感服务调大队列前必须做基线对比,否则 P99 与超时率恶化后很难定位原因
  • 把 nr_requests 调得超过设备硬件能力(queue_depth 很小)会让排队时间集中在内核,表现为 await 飙升但吞吐不变
  • 该值不持久,重启后回到默认或被 udev/tuned 覆写,变更必须落到配置管理里才算生效

数据来源与参考

  • Linux 内核 Documentation/block/queue-sysfs.rst
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌