在 GPU 服务器上,监测 NVMe 实际读写带宽,最直接、最可靠的是 iostat。GPU 型号不会改变 Linux 块设备监控方法;重点是找到底层 nvme设备。
1. 找到挂载目录对应的 NVMe
例如你的数据目录是 /data0 :
findmnt -T /data0 -o TARGET,SOURCE,FSTYPE,OPTIONS
可能得到:
nvme2n1 disk 7T SOLIDIGM ... /data0
后续监测 /dev/nvme2n1。对于 bind mount,应监测底层 NVMe 块设备,而不是 /data0 这个目录。
2. 实时监测每块 NVMe 带宽
查看指定磁盘实时带宽:
iostat -dxm -y nvme2n1 1
其中:
| 字段 | 含义 |
|---|---|
rMB/s | 实际从磁盘读取的 MiB/s |
wMB/s | 实际写入磁盘的 MiB/s |
r/s、w/s | 每秒读写 IOPS |
rareq-sz、wareq-sz | 平均读写请求大小,KiB |
r_await、w_await | 读写请求平均延迟,包含排队时间,单位 ms |
aqu-sz | 平均请求队列深度 |
%util | 设备存在未完成 I/O 的时间比例 |
iostat -m 输出名义上是 MB/s,实际采用 MiB/s,即 1024×1024 字节。现代 NVMe 可以并行处理多个请求,因此 %util 接近 100% 不等于已经达到带宽上限;需要结合带宽、延迟和队列深度判断。
推荐重点观察:
rMB/s wMB/s r_await w_await aqu-sz
一般来说,如果出现:
带宽不再增长
+ aqu-sz 持续增长
+ await 明显升高
通常说明磁盘、PCIe 链路或上游 I/O 路径已经接近瓶颈。
获取某个磁盘每分钟读取和写入累积量
下面脚本每隔 60 秒读取一次 /sys/class/block/<device>/stat,输出:
- 最近一分钟的读取量、写入量
- 从脚本启动以来的累计读取量、写入量
#!/usr/bin/env bash
set -euo pipefail
# 用法:
# bash disk_io_per_minute.sh /dev/nvme0n1
# bash disk_io_per_minute.sh nvme0n1
#
# 可选:指定采样周期,默认 60 秒
# bash disk_io_per_minute.sh nvme0n1 60
device="${1:-}"
interval="${2:-60}"
if [[ -z "$device" ]]; then
echo "Usage: $0 <device> [interval_seconds]"
echo "Example: $0 /dev/nvme0n1 60"
exit 1
fi
device="$(basename "$device")"
stat_file="/sys/class/block/${device}/stat"
if [[ ! -r "$stat_file" ]]; then
echo "Error: cannot read ${stat_file}"
exit 1
fi
# /sys/class/block/<device>/stat:
# 第 3 个字段:累计读取扇区数
# 第 7 个字段:累计写入扇区数
# Linux 块设备统计中的每个扇区按 512 字节计算
read_io_stats() {
local fields
read -ra fields < "$stat_file"
read_sectors="${fields[2]}"
write_sectors="${fields[6]}"
}
format_mib() {
awk -v sectors="$1" \
'BEGIN { printf "%.2f", sectors * 512 / 1024 / 1024 }'
}
read_io_stats
previous_read="$read_sectors"
previous_write="$write_sectors"
total_read=0
total_write=0
printf "%-19s %15s %15s %18s %18s\n" \
"Time" "Read MiB/min" "Write MiB/min" \
"Total Read MiB" "Total Write MiB"
while sleep "$interval"; do
read_io_stats
current_read="$read_sectors"
current_write="$write_sectors"
# 处理设备统计计数器重置的情况
if (( current_read >= previous_read )); then
delta_read=$((current_read - previous_read))
else
delta_read=0
fi
if (( current_write >= previous_write )); then
delta_write=$((current_write - previous_write))
else
delta_write=0
fi
total_read=$((total_read + delta_read))
total_write=$((total_write + delta_write))
printf "%-19s %15s %15s %18s %18s\n" \
"$(date '+%F %T')" \
"$(format_mib "$delta_read")" \
"$(format_mib "$delta_write")" \
"$(format_mib "$total_read")" \
"$(format_mib "$total_write")"
previous_read="$current_read"
previous_write="$current_write"
done
保存并运行:
chmod +x disk_io_per_minute.sh
./disk_io_per_minute.sh /dev/nvme0n1
示例输出:
Time Read MiB/min Write MiB/min Total Read MiB Total Write MiB
2026-07-03 15:01:00 1024.50 256.25 1024.50 256.25
2026-07-03 15:02:00 2048.00 512.00 3072.50 768.25
2026-07-03 15:03:00 128.00 64.00 3200.50 832.25
这里的 Read MiB/min 和 Write MiB/min 是该采样周期内底层磁盘实际完成的 I/O 量,不是文件系统层面的文件大小变化。
3. 查看是哪个进程在读写
使用 pidstat
pidstat -d -p ALL 1
只监测特定进程:
pidstat -d -p <PID> 1
主要字段:
kB_rd/s 进程触发的磁盘读取速度
kB_wr/s 进程触发或将要触发的磁盘写入速度
pidstat -d 提供进程级磁盘 I/O 统计,但写入可能经过 page cache,因此它与底层磁盘瞬时带宽不一定完全同步。
使用 iotop
iotop -oPa
参数含义:
-o 只显示存在 I/O 的进程
-P 按进程聚合,而不是线程
-a 显示累计 I/O
查看实时值可以用:
iotop -oP
iotop 支持在进程、线程、当前速率和累计量之间切换。
4. 同时观察所有 NVMe 的简化命令
watch -n 1 '
iostat -dxm -y 1 1 |
awk "NR==1 || /^Device/ || /^nvme/"
'
也可以同时观察磁盘和进程:
# 终端 1:物理磁盘带宽
iostat -dxm -y 1
# 终端 2:进程 I/O
pidstat -d -p ALL 1
这是排查推理服务、模型加载、KV Cache 落盘、checkpoint 加载等 I/O 问题时最实用的组合。
5. 查看 NVMe SMART 和累计读写量
nvme list
nvme smart-log /dev/nvme2
持续查看:
watch -n 5 '
nvme smart-log /dev/nvme2 |
grep -E "data_units_read|data_units_written|temperature|percentage_used|media_errors"
'
这里的 data_units_read 和 data_units_written 是累计值,不是瞬时带宽。每个 data unit 对应 1000 × 512 字节,可以通过两次采样的差值计算较长时间窗口的平均带宽。SMART 更适合观察累计写入量、温度、寿命和错误,不适合替代 iostat 做秒级监控。NVIDIA 官方说明 DGX 默认预装了 nvme-cli。
6. 检查 PCIe 链路是否降速
先查看 NVMe 控制器:
lspci -D | grep -i 'Non-Volatile memory'
例如设备地址是 0000:41:00.0:
lspci -s 0000:41:00.0 -vv |
grep -E 'LnkCap:|LnkSta:'
重点关注:
LnkCap: Speed 32GT/s, Width x4
LnkSta: Speed 32GT/s, Width x4
如果能力是 x4,实际却变成 x2;或者能力支持更高速度但实际协商速度较低,就可能存在插槽、转接板、BIOS、固件或链路问题。
注意:LnkSta 只表示当前 PCIe 协商速率和宽度,不是实时 PCIe 流量。
7. 检查 NVMe 的 NUMA 归属
GPU服务器通常有多个 CPU Socket、PCIe Root Port 和多块 NVMe。I/O 进程跑在远端 NUMA 节点时,可能增加跨 Socket 流量。
查看 NVMe 对应 NUMA 节点:
cat /sys/class/nvme/nvme2/device/numa_node
查看系统 NUMA:
numactl -H
查看 PCIe 拓扑:
lspci -tv
查看进程 CPU 位置:
ps -o pid,psr,comm -p <PID>
将压测或 I/O 进程绑定到 NVMe 所在 NUMA 节点:
numactl --cpunodebind=1 --membind=1 <command>
NVIDIA 的 GPU参考架构强调将 PCIe 连接分散到不同 CPU Socket 和 Root Port;当多块盘同时读写时,应分别观察每块 NVMe,而不是只看总带宽。
8. 不依赖 iostat,直接读取内核计数器
Linux 在下面的位置提供块设备累计统计:
cat /sys/block/nvme2n1/stat
其中第 3 个字段是累计读取扇区数,第 7 个字段是累计写入扇区数;内核统计中的扇区固定按 512 字节计算。对两次采样做差即可计算带宽。
一个简单的每秒监测脚本:
#!/usr/bin/env bash
dev="${1:-nvme2n1}"
interval="${2:-1}"
stat="/sys/block/${dev}/stat"
read_stats() {
read -r _ _ read_sectors _ _ _ write_sectors _ _ < "$stat"
}
read_stats
prev_read=$read_sectors
prev_write=$write_sectors
while sleep "$interval"; do
read_stats
read_mib=$(awk -v now="$read_sectors" \
-v prev="$prev_read" -v sec="$interval" \
'BEGIN { printf "%.2f", (now-prev)*512/1024/1024/sec }')
write_mib=$(awk -v now="$write_sectors" \
-v prev="$prev_write" -v sec="$interval" \
'BEGIN { printf "%.2f", (now-prev)*512/1024/1024/sec }')
printf '%s read=%10s MiB/s write=%10s MiB/s\n' \
"$(date '+%F %T')" "$read_mib" "$write_mib"
prev_read=$read_sectors
prev_write=$write_sectors
done
运行:
bash nvme_bw.sh nvme2n1 1
建议直接使用的组合
# 查看磁盘对应关系
lsblk -o NAME,TYPE,SIZE,MODEL,MOUNTPOINTS
# 每块盘的实际带宽、延迟和队列
iostat -dxm -y 1
# 查找产生 I/O 的进程
pidstat -d -p ALL 1
# 检查 NVMe 温度、寿命和错误
nvme smart-log /dev/nvme2
# 检查 PCIe 链路
lspci -s <NVME_PCI_BDF> -vv | grep -E 'LnkCap:|LnkSta:'
其中,判断 NVMe 实时读写带宽以 iostat 的 rMB/s、wMB/s 为准;pidstat/iotop 用于定位进程,nvme smart-log 用于健康和累计量,lspci 用于排查链路降速。
sysstat介绍
如需安装 iostat(sysstat):
# Ubuntu/Debian
apt install -y sysstat
# RHEL/Rocky/CentOS
dnf install -y sysstat
每秒刷新一次:
iostat -dxm -y 1
只看 NVMe:
iostat -dxm -y 1 | grep --line-buffered -E '^Device|^nvme'
当你安装了 sysstat
之后,除了 iostat
,你还会获得以下用于检测 Linux 性能的常用武器: [1, 2]
sar:系统活动报告器,可以说是sysstat的核心,负责收集、汇报并存储系统的历史性能数据。mpstat:专门用来监控多处理器(Multi-Processor)中每一个核心的 CPU 利用率。pidstat:用来监控具体某一个进程的 CPU、内存、线程及 I/O 状态。cifsiostat:用于监控 CIFS(通用因特网文件系统)的网络文件 I/O 状态。
sysstat
提供了覆盖全系统的 Linux 性能监控能力。它不仅能进行实时状态查看
,还能通过后台守护进程(sysstat.service
)自动收集历史性能数据
。
以下是 sysstat
的 6 大核心监控维度及对应工具:
1. 中央处理器 (CPU) 监控
- 整体与多核状态 :监控整体 CPU 使用率(用户态、内核态、空闲、等待 I/O 等),并能展示每个独立 CPU 核心的负载。
- 进程与线程级监控 :追踪单个进程或线程的 CPU 消耗、上下文切换次数(Context Switches)。
- 对应工具
:
mpstat、sar -u、pidstat -u
2. 存储与输入/输出 (I/O) 监控
- 磁盘设备吞吐 :监控每个块设备的读写速度(kB/s)、每秒读写次数(IOPS)。
- 磁盘饱和度分析 :查看磁盘队列长度、服务时间、单个 I/O 请求的平均等待时间以及磁盘利用率(%util) 。
- 文件系统与网络文件系统 :支持监控 Linux 文件系统节点,以及 NFS / CIFS 等网络文件系统的 I/O 状态。
- 对应工具
:
iostat、sar -d、pidstat -d、nfsiostat、cifsiostat
3. 内存与交换分区 (Memory & Swap)
- 内存利用率 :监控物理内存的空闲、已用、缓冲(Buffer)和缓存(Cache)大小。
- 大页内存与脏页 :监控系统 Anonymous Huge Pages 的使用情况,以及等待刷入磁盘的脏页(Dirty Pages)数量。
- 交换分区活跃度 :监控 Swap 分区的使用量,以及每秒内存页入/页出(Paging)的速率。
- 对应工具
:
sar -r、sar -R、sar -W、pidstat -r
4. 网络 (Network) 监控
- 网卡吞吐与报文 :监控每个网络接口(如 eth0, wlan0)每秒接收和发送的数据量(kB/s)及数据包数量。
- 网络错误与丢包 :统计网卡接收/发送时的错误数、丢包数和帧对齐错误。
- 网络协议栈统计 :监控 TCP、UDP、ICMP 等传输层和网络层协议的流量、错误段及重传率。
- 套接字 (Sockets) :统计当前系统处于使用中、监听中或处于特定状态的 TCP/UDP 套接字数量。
- 对应工具
:
sar -n DEV、sar -n EDEV、sar -n TCP、sar -n SOCK
5. 系统负载与内核参数
6. 电源管理与硬件(特定平台)
- 队列长度与负载:统计系统运行队列长度(Run Queue)、进程总数以及 1/5/15 分钟的系统平均负载(Load Average)。
- 内核资源限制 :监控当前系统已打开的文件句柄数(File Handles)、Inode 状态和伪终端数量。
- 对应工具
:
sar -q、sar -v - 设备能耗 :在支持的硬件上,监控 CPU 频率、温度以及风扇转速。
- 对应工具
:
sadc(底层收集器)、sar -m

298

被折叠的 条评论
为什么被折叠?



