☰
系统性能排查六要素:CPU、内存、磁盘、网络与GPU监控实战
2026/10/27 7:51:26 网站建设 项目流程

系统性能排查是后端开发和运维工作中绕不开的核心技能。无论是上线前压测、线上告警处理,还是日常资源规划,都需要先看懂机器的运行状态,才能判断瓶颈到底落在哪里。很多开发者在排查问题时习惯只看某个单一指标,比如 CPU 飙高就以为是计算密集,结果优化了大半天才发现真正的瓶颈是磁盘 I/O 或网络重传。本文围绕 GPU 使用率、CPU 使用率、CPU 上下文切换、内存使用率、磁盘 I/O、网络 I/O 六个维度展开,结合 Linux 常用监控工具与完整分析方法,说明每一项指标如何采集、如何解读、如何联动定位系统瓶颈,并给出生产环境下的最佳实践。

1. 性能监控的底层逻辑与核心概念

1.1 为什么需要同时观察六类指标

一台服务器的资源是有限的,任何程序运行都会消耗 CPU、内存、磁盘、网络和 GPU(如果涉及模型训练或推理)。这些资源不是孤立工作的,例如一次普通的数据库查询,会同时产生 CPU 计算、内存读取、磁盘 I/O、网络传输;一个深度学习训练任务,会同时消耗 GPU 算力、CPU 数据预处理能力、内存带宽和磁盘读取能力。如果只观察其中一个指标,很容易被表面现象误导。典型的例子是:GPU 利用率很低,但训练速度非常慢,表面看是 GPU 资源不足,实际可能是 CPU 数据加载太慢,GPU 一直在等待数据,这时候真正需要优化的是数据加载管道。

因此,系统性能监控的核心思路是:把六个维度的指标放在同一时间轴上对比分析,通过“资源使用率 + 等待状态 + 吞吐量”的组合判断瓶颈位置。单看使用率高不高没有意义,重点是搞清楚谁在等谁。

1.2 关键指标的分工定位

六类指标可以从“资源类型”和“瓶颈方向”两个维度进行分类:

指标资源类型重点关注方向典型工具
GPU 使用率计算加速资源算力是否打满、显存容量、GPU 等待nvidia-smi、nvtop
CPU 使用率计算资源用户态/内核态占比、I/O 等待、负载top、vmstat、mpstat
CPU 上下文切换调度/内核开销线程数量、锁竞争、中断处理vmstat、pidstat
内存使用率存储资源可用内存、缓存、换页、OOM 风险free、vmstat
磁盘 I/O存储 I/O吞吐量、IOPS、延迟、队列长度iostat、iotop
网络 I/O网络资源带宽、PPS、重传、握手队列sar、nload、ifstat

从瓶颈方向来看:

  • CPU 使用率高,代表计算资源紧张,或者程序写得不合理。
  • CPU 使用率不高但系统响应慢,可能瓶颈在磁盘、网络或锁等待。
  • 上下文切换频繁,代表系统在大量切换执行任务,可能线程过多或中断过多。
  • 内存使用率高,需要区分是缓存占满还是应用真实消耗。
  • 磁盘 I/O 饱和,通常表现为 CPU 的 iowait 升高,进程阻塞在 I/O 上。
  • 网络 I/O 饱和,通常表现为延迟升高、重传增加、丢包率上升。

这些指标之间是相互印证的关系。单独看任何一个指标都有局限,组合在一起才能还原出系统的真实运行链路。

2. 环境准备与监控工具安装说明

2.1 操作系统与工具链

本文示例以 Linux 环境为主,因为大多数服务器、容器宿主机和 AI 训练节点都运行在 Linux 上。如果你使用的是 CentOS、Ubuntu、Debian、Rocky Linux,下面这些工具基本都可以通过系统包管理器安装。Windows 环境下的性能监控(如 PerfMon 和任务管理器)不在本文范围内,但分析思路完全相通。

工具清单如下:

工具所属包核心用途
top / htopprocps / htop实时查看进程、CPU、内存
mpstatsysstat查看每个 CPU 核心的使用率明细
vmstatprocps查看系统整体的运行队列、内存换页、CPU 等待
pidstatsysstat按进程维度查看 CPU、上下文切换、I/O
freeprocps查看内存总量、使用量、缓存
iostatsysstat查看磁盘 I/O 吞吐量、利用率、等待时间
iotopiotop按进程实时查看磁盘 I/O
sarsysstat历史性能数据采集与回放
nvidia-smiNVIDIA 驱动自带查看 GPU 使用率、显存、温度、功耗
nvtopnvtopGPU 监控的交互式界面
nload / iftopnload / iftop实时查看网络流量
ss / netstatiproute2 / net-tools查看网络连接状态、队列信息

需要注意,不同发行版安装命令不同。CentOS/RHEL 系使用yum install -y sysstat htop nload iftop,Ubuntu/Debian 系使用apt install -y sysstat htop nload iftop。NVIDIA 驱动本身自带 nvidia-smi,无需单独安装;nvtop 需要额外安装,并且会读取 NVML 库来获取 GPU 信息。

版本方面,不同版本的 sysstat 输出字段会有细微差别,比如较新的 iostat 增加了更多列。本文示例以常见稳定版本输出为准,实际使用中只需关注关键列即可。

2.2 确保监控数据可回溯

临时看实时数据可以使用 top、vmstat 这类工具,但生产环境更推荐搭配 sar 做历史数据采集。sysstat 安装后,需要确认/etc/cron.d/sysstat或 systemd 定时器已经启用,默认每 10 分钟采集一次数据。使用下面命令查看当前是否正常采集:

sar -u 1 3

如果输出有数据,说明历史采集已生效。如果没有输出,先启动 sysstat 服务:

systemctl start sysstat systemctl enable sysstat

有了历史数据,线上出问题时才能回顾“故障发生前半小时内存是怎么变化的”“磁盘 I/O 是什么时候开始飙高的”,这一点在故障复盘时非常关键。

3. GPU 使用率:AI 训练的算力窗口

3.1 使用 nvidia-smi 查看 GPU 基础状态

在深度学习训练、模型推理、科学计算场景中,GPU 使用率是最直观的算力指标。执行命令:

nvidia-smi

输出信息非常丰富:

+-----------------------------------------------------------------------------+ | NVIDIA-SMI 525.85.12 Driver Version: 525.85.12 CUDA Version: 12.0 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 Tesla T4 On | 00000000:00:1E.0 Off | 0 | | N/A 54C P0 31W / 70W | 2116MiB / 15360MiB | 12% Default | | | | N/A | +-------------------------------+----------------------+----------------------+

关键字段的含义:

  • GPU-Util是 GPU 计算单元利用率,表示采样时间内 GPU 上活跃计算任务占用的时间比例。需要注意,12% 不代表 GPU 只用了 12% 的容量,它代表有 12% 的时间有核在执行计算指令,中间大量时间可能是在等待数据。
  • Memory-Usage是显存使用量,深度学习场景中显存不足会直接报 CUDA Out Of Memory,所以显存和利用率需要同时看。
  • Temp是 GPU 温度,高负载下温度长期接近或超过 85°C 时需要检查散热或降频。
  • Pwr:Usage/Cap是当前功耗和最大功耗,功耗接近上限说明 GPU 已经满载工作。

3.2 如何正确理解 GPU 利用率偏低

训练模型时如果 GPU 利用率长期低于 50%,通常不是 GPU 本身算力不够,而是训练管道中存在瓶颈。常见原因包括:

  • CPU 负责数据加载和预处理,如果 CPU 处理不过来,GPU 只能空转等待。
  • 数据读取走磁盘,磁盘 I/O 跟不上数据加载速度。
  • 训练脚本中每个 step 内做了大量同步操作、日志打印或评估逻辑。
  • 模型存在大量小算子,GPU 计算密集度不够,启动和调度开销占比过高。
  • 多卡训练时通信开销过大,GPU 在等待参数同步。

使用nvidia-smi dmon可以按固定间隔持续输出 GPU 状态,适合后台采集:

nvidia-smi dmon -s puct -d 1

-s参数指定要显示的指标组,p代表功耗,u代表利用率,c代表计算相关统计,t代表温度,-d 1表示每秒采集一次。如果 GPU 利用率和功耗同时偏低,很大概率是数据供给不足或任务同步等待。

3.3 在训练脚本中实时监控 GPU 状态

除了在宿主机上执行命令,也可以在 Python 训练脚本中通过pynvml或nvidia-ml-py获取 GPU 信息,把 GPU 利用率和显存写入日志,方便分析训练过程中 GPU 的变化曲线。示例思路如下:

import pynvml import time pynvml.nvmlInit() handle = pynvml.nvmlDeviceGetHandleByIndex(0) for _ in range(10): util = pynvml.nvmlDeviceGetUtilizationRates(handle) mem = pynvml.nvmlDeviceGetMemoryInfo(handle) print(f"GPU 利用率: {util.gpu}%, 显存占用: {mem.used // 1024**2} MB") time.sleep(1)

这不是生产级代码,但给出了一个很关键的思路:当训练日志和 GPU 监控日志时间轴对齐后,就能定位到某个具体 step 是否发生了 GPU 空等问题。

4. CPU 使用率:从整体到单核的逐层拆解

4.1 top 命令中的 CPU 使用率不代表全部

执行top后,最上方会看到类似这样的 CPU 汇总:

%Cpu(s): 20.3 us, 5.2 sy, 0.0 ni, 73.8 id, 0.5 wa, 0.0 hi, 0.2 si, 0.0 st

字段含义:

  • us是用户态 CPU 占比,应用程序计算逻辑消耗的 CPU。
  • sy是内核态 CPU 占比,系统调用、驱动、内核管理消耗的 CPU。
  • ni是 nice 值调整过的进程 CPU 占比,通常用于低优先级任务。
  • id是空闲占比,越大说明 CPU 越空闲。
  • wa是 I/O 等待占比,代表 CPU 在等待磁盘或网络 I/O 完成。
  • hi是硬件中断占比,通常与网卡、磁盘控制器等硬件处理相关。
  • si是软件中断占比,网络收发、定时任务等会消耗这部分 CPU。
  • st是被虚拟机管理程序偷走的 CPU 时间占比,在云服务器上常见。

这里最容易被忽略的是wa。CPU 使用率只有 20%,但wa占 30%,说明进程并没有吃饱 CPU,而是大量时间卡在 I/O 上。此时操作系统显示 CPU 在等待,实际上业务响应慢的根源是磁盘,不是 CPU。

按P键可以按 CPU 占用排序,快速定位消耗最高的进程。按1可以展开每个 CPU 核心的使用情况,便于判断是某个核打满还是均匀负载。

4.2 使用 mpstat 查看多核分布

多核机器上,单个进程可能只跑在一个核上。如果程序是单线程的,即使其他核都空闲,这个核也可能达到 100%,从整体 CPU 使用率上看可能只有 12.5%。排查这类问题需要逐核分析:

mpstat -P ALL 2 5

输出示例:

Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle Average: all 30.25 0.00 5.10 2.30 0.00 0.85 0.00 0.00 0.00 61.50 Average: 0 90.50 0.00 8.25 0.00 0.00 0.50 0.00 0.00 0.00 0.75 Average: 1 5.10 0.00 2.30 3.20 0.00 0.40 0.00 0.00 0.00 89.00

可以看到整体空闲 61.5%,但 CPU 0 已经几乎打满。这种情况下的优化方向是:让单线程程序改用多进程/多线程,或者通过taskset做绑核优化,避免线程在不同核之间频繁迁移。

4.3 CPU 使用率突高的排查路径

遇到 CPU 使用率突高,按以下顺序排查:

  1. 先用top -c找到 CPU 占用最高的进程。
  2. 用top -Hp <pid>查看该进程内部哪些线程消耗 CPU 最高。
  3. 如果是 Java 应用,使用jstack导出线程栈,结合线程 ID 定位到具体代码位置。
  4. 如果是 Python 应用,使用py-spy dump --pid <pid>查看当前 Python 函数调用栈。
  5. 如果是 Node.js 应用,使用node --prof-process分析 CPU profile。

不要一看到 CPU 高就直接改代码。先确认是业务线程跑满、GC 线程跑满、还是定时任务集中执行,再针对性处理。例如 Java 应用 GC 线程占满 CPU 时,盲目加业务线程只会让情况更糟。

5. CPU 上下文切换:线程调度与内核开销的信号灯

5.1 什么是 CPU 上下文切换

操作系统在多个线程之间分配 CPU 时间片时,需要保存当前线程的执行状态(寄存器、程序计数器、内核栈等),再加载下一个线程的状态,这就是一次上下文切换。频繁的上下文切换本身会消耗 CPU 时间,更严重的是会导致 cache 失效,后续访问内存的延迟变高。

Linux 中,进程、线程的切换是上下文切换,中断处理也是上下文切换的一种。前者称为任务切换,后者包括硬件中断和软件中断处理带来的切换开销。

使用vmstat 1 5查看cs列:

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 2 0 0 163456 512 20480 0 0 0 0 1200 8000 12 5 82 0 0

cs列就是每秒上下文切换次数。单独一次看可能很难判断好坏,需要结合 CPU 核心数和线程规模来评估。判断思路:

  • 对于 8 核机器,每秒上下文切换 8000 次(约每核 1000 次/秒)通常处于正常范围。
  • 如果每秒超过 20000 次并且持续增长,大概率存在线程过多或锁竞争问题。
  • 上下文切换高但 CPU 整体空闲,说明线程在频繁睡眠/唤醒,典型的锁等待场景。
  • 上下文切换高且si软中断占用高,可能是网络小包洪峰或网卡多队列配置不合理。

5.2 按进程查看上下文切换

使用pidstat -w可以按进程维度观察:

pidstat -w 2 5

输出中cswch/s是自愿上下文切换次数,nvcswch/s是非自愿上下文切换次数。这里有一个非常重要的区分:

  • 自愿切换高,说明线程在等待锁、等待 I/O、主动 sleep。
  • 非自愿切换高,说明线程的时间片被抢占,常见原因是线程数量远大于 CPU 核心数,或者有更高优先级的任务在抢占。

生产环境中,如果nvcswch/s非常高,优先检查线程池大小是否设置过大。典型误区是,为了提升并发能力把线程池设成几千,结果大量线程都在等待任务,反而导致频繁上下文切换,吞吐量下降。这时候减少线程数通常比增加线程数更有效果。

5.3 软中断与硬中断带来的切换开销

网络数据包到达网卡后,会触发硬中断通知 CPU 处理;硬中断处理完后,剩余工作交给软中断。高 PPS(每秒数据包数)场景下,软中断可能长期占满某个 CPU 核心。检查方法:

cat /proc/softirqs cat /proc/interrupts

如果NET_RX软中断集中在 CPU 0 上,说明网卡没有开启多队列,或者 CPU 亲和性没有配置好。现代 Linux 和网卡驱动支持 RSS(Receive Side Scaling),可以将不同队列的中断绑定到不同 CPU 核心,避免单核软中断打满。这是网络密集型服务需要重点关注的方向。

6. 内存使用率:从 free 输出到 OOM 风险

6.1 free 命令各列的真实含义

执行free -h:

total used free shared buff/cache available Mem: 31Gi 12Gi 2.1Gi 100Mi 17Gi 18Gi Swap: 4.0Gi 512Mi 3.5Gi

这里容易搞混的是free和available。free是完全没有被使用的物理内存,buff/cache是 Linux 用来缓存磁盘文件和页面缓存的内存。这部分内存在应用需要时可以自动回收,所以真正可用内存要参考available列。系统显示 2.1Gi free,不代表内存不够用,因为 17Gi buff/cache 在需要时可以释放。

真正需要警惕的是available持续下降并接近 0,这意味系统可能要开始 swap 或触发 OOM Killer。当si(从磁盘交换入内存)和so(从内存交换出到磁盘)两列持续有数值时,说明内存已经在频繁换页,性能会显著下降。

6.2 按进程定位内存占用

使用top -o %MEM可以按内存占用率排序,快速找出内存大户。但 Linux 中进程 RSS 有两个需要注意的地方:

  • RSS 是进程独占的物理内存,不包含共享库中其他进程也引用的部分。
  • 多个进程通过fork()生成时,会共享父进程的物理内存页,RSS 会出现重复计数。

如果要精确分析,可以查看/proc/<pid>/smaps中的 PSS(Proportional Set Size),它把共享内存按进程数分摊计算。日常使用smem工具更方便:

smem -rk | head -20

6.3 内存问题的常见表现

内存问题不只是“不够用”这一种。实际生产环境中的典型场景:

现象可能原因查看方式
available 持续低,无明显进程占用页缓存持续增长,但回收不及时cat /proc/meminfo查看 MemAvailable
应用报 OOM,但系统内存还有剩余cgroup 内存限制或容器内存限制cat /sys/fs/cgroup/memory/memory.limit_in_bytes
大量换页导致 CPU sys 高swap 频繁读写vmstat 中 si/so 持续非零
频繁执行 GC 或进程崩溃堆内存/缓存设置不合理,内存碎片应用日志 + GC 日志

在容器环境中,还要注意容器通过 cgroup 限制内存后,free看到的是宿主机内存,而不是容器内存。判断容器是否内存超限,需要查看 cgroup 目录下的memory.max和memory.current,不能只看free输出。

7. 磁盘 I/O:延迟、吞吐与利用率

7.1 使用 iostat 拆分磁盘状态

执行:

iostat -x 2 5

关键列含义:

  • r/s和w/s是每秒读/写请求次数,对应 IOPS。
  • rkB/s和wkB/s是每秒读/写吞吐量。
  • await是 I/O 请求处理的平均等待时间(毫秒),包含排队时间和实际处理时间。
  • %util是设备忙绿时间占比,反映磁盘的繁忙程度。
  • svctm目前 iostat 已不再推荐使用该值估算服务时间,更多作为参考。

%util接近 100% 代表磁盘已经饱和,但不同磁盘型号对饱和的定义不同。普通机械盘在 80% 以上基本接近极限,而 NVMe SSD 即使 %util 到 100%,延迟可能还在毫秒级,整体性能依然可以接受。因此await才是更直观的体验指标:

  • 机械盘 await 在 10~20ms 以内算正常。
  • SSD 在 1~2ms 以内算正常。
  • 云盘受网络和虚拟化影响,延迟标准要根据云厂商文档确定。

7.2 按进程定位磁盘读写

iostat看到的是系统整体磁盘状态,定位哪个进程在产生 I/O 需要使用iotop:

iotop -oP

-o只显示正在执行 I/O 的进程,-P显示进程而不是线程。对于 Java 应用,还可以通过lsof -p <pid> | grep deleted发现日志文件被删除仍被占用、磁盘空间无法释放的问题。这类细节问题在生产环境很常见,但容易被忽略。

7.3 磁盘 I/O 与文件系统层面的隐藏坑

磁盘延迟不只来自硬件本身,还来自文件系统、锁和配置:

  • ext4的auto_da_alloc特性可能导致数据库类应用在fsync时性能下降。
  • 容器使用 overlayfs 时,大量小文件读写会放大 I/O 开销。
  • 日志框架在使用同步刷盘模式时,每条日志都会触发fsync,导致 I/O 吞吐大幅下降,但 iostat 中%util可能并不高,因为等待在发生在锁上。

遇到磁盘 I/O 异常时,先看await是否高,再看%util是否打满,最后再往上定位是文件系统、应用层还是硬件本身。

8. 网络 I/O:带宽、PPS 与连接跟踪

8.1 查看实时网络流量

使用sar -n DEV 2 5可以查看网络接口的实时吞吐:

Average: IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil Average: eth0 12000.50 11020.30 15360.20 12440.10 0.00 0.00 0.00 6.20

rxpck/s和txpck/s是每秒收发包数量,rxkB/s和txkB/s是每秒收发字节数。需要注意,带宽打满不代表 PPS 打满,反之亦然。比如一个网卡带宽 10Gbps,但每个包只有 64 字节,小包洪峰可能导致 PPS 达到上限,而带宽使用率只有 5%。这种情况下,看带宽看不出问题,但业务可能已经出现大量丢包和延迟。

常用的实时工具还有:

nload eth0 iftop -i eth0

nload提供带宽曲线,iftop可以按连接查看流量来源和目的地址。

8.2 检查网络重传与握手队列

网络问题最常见的一种是:带宽没有打满,但接口响应变慢。这时候需要检查 TCP 层:

netstat -s | grep -i retrans

如果重传率持续上升,说明网络链路存在丢包,常见原因包括:

  • 内核缓冲区不足,net.core.rmem_max和net.core.wmem_max设置过小。
  • 网卡队列溢出,ethtool -S eth0中查看rx_dropped和rx_missed。
  • 突发流量超过网卡处理能力。

查看 TCP 握手队列溢出情况:

ss -lnt

输出中Send-Q和Recv-Q在监听状态下的含义不同:对监听套接字,Recv-Q表示当前已完成握手但尚未被应用 accept 的连接数,如果持续增大说明应用 accept 速度跟不上;Send-Q表示握手队列最大长度。如果这个值等于net.core.somaxconn并且持续满,说明并发连接涌入太快。

9. 综合实战:一次多指标联动定位瓶颈的排查过程

9.1 场景描述

线上一个常规业务接口出现延迟告警,从原本平均 80ms 上升到 1.5s。初步怀疑是数据库慢查询,但 DBA 反馈数据库没有异常。这时需要系统性地把六类指标都拉出来对比。

9.2 监控数据采集

在告警时间段收集以下数据:

top -b -n 2 -d 3 > top.log vmstat 1 5 > vmstat.log pidstat -w 1 5 > ctx.log iostat -x 1 5 > iostat.log sar -n DEV 1 5 > network.log

如果机器带有 GPU,还需要观察训练任务或推理服务的 GPU 利用率。

9.3 数据分析与结论推断

假设采集到的数据呈现以下特征:

指标数值/状态初步判断
CPUus75%计算负载较高
CPUwa1%大概率不是磁盘等待
上下文切换45000 次/秒明显偏高,8 核机器单核约 5600 次/秒
非自愿切换28000 次/秒线程被频繁抢占
内存 available20GB内存充足
磁盘 %util12%磁盘压力不大
网络 PPS60000 包/秒中高流量,但未打满

只看 CPU 和磁盘,会得出“CPU 计算压力大”的结论。但结合上下文切换后,真正的疑点是:非自愿切换占比过高,说明系统中有大量线程在竞争 CPU 时间片。线程数量多,而且每个线程都在抢 CPU,才会导致这种状态。

继续使用下列命令确认进程线程数:

ps -eLf | wc -l

如果线程数达到数千,而 CPU 核心只有 8 核,那么线程调度必然带来大量切换开销。这种情况下,业务接口的大部分时间消耗在线程切换和等待 CPU 时间片上,而不是在真正执行业务逻辑。

9.4 解决方案与验证

针对线程过多导致上下文切换过高的问题,优化方向优先选择调整应用线程池大小:

  • 将核心线程数从 200 调整为 64。
  • 将最大线程数从 2000 调整为 200。
  • 配合队列容量控制,避免任务无线排队。

调整后重新采集数据,上下文切换从 45000 次/秒下降到 12000 次/秒,接口延迟恢复到 90ms 左右。这里的关键启发是:如果一开始只盯着 CPU 使用率,可能会增加机器配置而不是调整线程池,问题没有解决还白白增加成本。把 CPU、上下文切换和线程数放在一起看,才能找到性价比最高的优化点。

10. 常见问题与排查清单

10.1 常见问题速查表

问题现象常见原因解决思路
GPU 利用率低,训练速度慢CPU 数据加载成为瓶颈优化 DataLoader 的 num_workers,检查磁盘读取速度
GPU 利用率低,显存占满模型过大或 batch size 过大降低 batch size,开启梯度累积
CPU 使用率高但业务不复杂死循环、正则回溯、GC 频繁抓取线程栈/函数调用栈定位热点
上下文切换高且自愿切换多锁竞争、线程 sleep 频繁减少锁粒度,优化任务队列模型
上下文切换高且非自愿切换多线程数远超核心数调整线程池大小
available 内存低但 RSS 不高页缓存占用量大确认是否有大量文件读操作,必要时调适 vm.dirty_ratio
应用报 OOM 但系统内存充足容器/cgroup 内存限制查看 cgroup 内存限制并合理配置
磁盘 %util 高,await 高磁盘达到性能上限迁移到 SSD、减少随机小 I/O、增加副本
磁盘 %util 不高但应用慢文件系统锁、日志 fsync 频繁调整日志刷盘策略,检查文件系统状态
带宽不高但延迟升高TCP 重传、握手队列满检查重传率、somaxconn、rmem/wmem
PPS 高且软中断集中在单核网卡多队列未开启开启 RSS,设置中断亲和性

10.2 排查清单

现场问题发生时,强烈的建议按以下顺序保存快照,而不是先重启机器:

  • [ ] 保存top -b -n 3输出,确认 CPU 和负载情况。
  • [ ] 保存vmstat 2 10输出,确认上下文切换和 I/O 等待。
  • [ ] 保存iostat -x 2 10,确认磁盘压力。
  • [ ] 保存sar -n DEV 2 10和ss -s,确认网络状态。
  • [ ] 保存free -h和cat /proc/meminfo,确认内存分布。
  • [ ] 如果涉及 GPU,执行nvidia-smi dmon -s puct -d 1持续采集。
  • [ ] 记录应用日志中最近 10 分钟的异常。
  • [ ] 保存dmesg -T | tail -100,排查内核级报错和 OOM。

有了这些数据,再结合上面六类指标的分析方法,就能逐步缩小范围,最终定位到具体进程和代码层面。

11. 最佳实践与工程建议

11.1 建立持续监控与历史数据基线

临时执行top和vmstat只能看到当下状态,无法反映业务高峰期的真实水位。建议在每台机器上开启 sysstat 历史采集,同时配置 Prometheus + node_exporter + Grafana 这类开源监控方案。node_exporter 默认就暴露了 CPU、内存、磁盘、网络等指标,配合告警规则可以及时发现指标异常。对于 GPU 机器,可以部署 DCGM Exporter(NVIDIA 官方出品),暴露 GPU 利用率、显存使用、温度、功耗等指标到 Prometheus。

监控数据的另一层价值是建立基线。只有知道正常业务高峰时 CPU 是多少、上下文切换是多少、磁盘 await 是多少,才能给告警阈值设置合理参数。没有基线的告警,要么频繁误报,要么错过真正的异常。

11.2 配置指标告警时使用组合条件

单指标告警容易误判。举例来说,CPU 使用率高并不一定代表需要扩容,可能只是定时任务在跑;上下文切换高但 CPU 和业务延迟都正常,可能只是并发量正常,不必报警。更具参考价值的告警规则是基于组合条件的,比如:

  • CPUiowait大于 20% 且磁盘avgqu-sz大于核数。
  • 上下文切换大于基线 2 倍 且 请求错误率上升。
  • GPU 利用率低于 30% 且 训练作业未结束。

告警的目的不是暴露所有指标,而是在影响业务之前提前预警。

11.3 重视资源隔离与容量规划

多租户场景下,容器和虚拟机之间要配置合理的资源限制。Kubernetes 中为 Pod 设置 CPU request/limit、内存 limit,并用ResourceQuota限制 namespace 总用量,可以避免单个应用耗尽宿主机资源。GPU 场景则需要使用 NVIDIA Device Plugin 或 MIG 功能做 GPU 资源隔离,避免多个任务争抢显存和算力。

容量规划方面,建议每个月至少复盘一次核心服务的资源水位,包括 CPU、内存、磁盘、网络和 GPU 的峰值与趋势。尤其是日志量增长比较快的服务,磁盘空间很容易被撑满;模型训练场景中,数据集规模扩大和模型参数量增大,都会直接影响显存和磁盘需求。

11.4 定期做全链路压测和故障演练

性能监控的最终目标不是“能看到指标”,而是“能在问题影响用户前提前发现并处置”。建议每季度做一次核心链路压力测试,模拟峰值流量下各资源的消耗情况,提前发现 CPU 上下文切换过高、数据库连接数打满、网络连接队列溢出等潜力问题。压测后不要只保留结果,要把问题修复记录和监控阈值调整记录都保留下来,作为下一轮监控优化的输入。

对于需要长期运行的训练任务,建议增加 GPU 利用率、数据加载耗时、显存增长趋势的自动化监控,并配置任务级探活。训练中断后自动恢复(checkpoint + 重启)比人工发现再处理可靠得多。

11.5 从指标到行动的闭环思维

在系统监控这个领域,指标本身不产生价值,基于指标的行动才产生价值。建议团队内部建立一套简单的处置流程:收到告警 -> 拉取时间窗口内全部指标 -> 判断瓶颈类型 -> 执行对应处置动作 -> 记录复盘结论 -> 更新基线或告警规则。这个闭环跑顺之后,同样的故障往往能被提前拦截,或者在几分钟内定位,而不是靠重启机器或盲目扩容来解决问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询