# GPU 服务器常见故障处理 ## 场景 GPU 服务器(训练卡、推理卡、显卡服务器)跑着任务出问题了:卡不见了、 `nvidia-smi` 报错、显存占用异常、训练突然中断、推理结果不对、温度报警。 这篇按「现象 → 定位 → 处理」整理,都是实际会遇到的。11111 ## 前置条件 * 能 SSH 上服务器,或者有 IPMI / iDRAC / iLO 的远程控制台 * 记下这台机器用的卡型(A100 / H100 / L40S / RTX 4090 / 国产卡等)和驱动版本 * 有**另一台同型号的机器**能对照,出问题时好比对 * 重要任务先确认有 checkpoint,别在故障状态硬跑 * 驱动和 CUDA 版本先记下来,换驱动前一定要记 ## 配置 ### 1\. nvidia\-smi 找不到卡 最常见。按顺序查: ```bash # 先看系统能不能看到卡 nvidia-smi # 报错信息分几种: # "command not found" → 驱动没装或 PATH 不对 # "Failed to initialize NVML" → 驱动加载了但和内核对不上 # "No devices were found" → 驱动在,但没找到硬件 ``` 三种情况分别处理: **驱动没装 / 装了但 PATH 不对** ```bash # 看驱动模块在不在 lsmod | grep nvidia ls /proc/driver/nvidia/version # 模块没加载,但文件在 modprobe nvidia nvidia-smi ``` **Failed to initialize NVML(驱动与内核版本不匹配)** 这是升级内核或升级驱动之后最常见的。内核头文件和驱动版本对不上: ```bash uname -r # 当前内核 cat /proc/driver/nvidia/version # 驱动带的内核版本 ls /usr/src/kernels/ # 有没有对应的头文件 ``` 两种修法: ```bash # 办法一:装当前内核的头文件,然后重装驱动 apt install linux-headers-$(uname -r) # 重新安装对应的 .run 驱动包(会重新编译内核模块) # 办法二:回退内核(更稳,但要重启) # 编辑 /etc/default/grub,把 GRUB_DEFAULT 改成旧内核 # update-grub && reboot ``` **No devices were found(驱动在,但卡不被识别)** ```bash # PCI 层面能不能看到卡 lspci | grep -i nvidia lspci -nn | grep -i "3d controller\|nvidia" # 内核有没有报错 dmesg -T | grep -iE "nvidia|nvrm|nouveau" | tail -30 ``` 几种典型: ```text "NVRM: Xid: ... GPU has fallen off the bus" → 卡掉了,PCIe 链路问题(见第 4 节) "NVRM: Failed to initialize GPU" → 卡本身或供电有问题 "unable to map BAR" → 内存映射失败,可能是 IOMMU 或 PCIe 设置 "Nouveau ... kernel driver" → 装了开源驱动,抢占了独显 ``` 如果是 nouveau 抢占了: ```bash # 禁用开源驱动 echo "blacklist nouveau" >> /etc/modprobe.d/blacklist-nouveau.conf echo "options nouveau modeset=0" >> /etc/modprobe.d/blacklist-nouveau.conf update-initramfs -u && reboot ``` **完全看不到卡(lspci 也没有)** 那就是硬件层面的问题了:卡没插好、供电没接、卡坏了、或者 PCIe 插槽有问题。 这个只能去机房看。 ### 2\. 驱动版本不对 / CUDA 版本不匹配 ```bash # 驱动版本 nvidia-smi --query-gpu=driver_version --format=csv,noheader # CUDA 运行时版本(注意:这是驱动最高支持的版本,不是装的 toolkit 版本) nvidia-smi | head -3 # PyTorch 实际用的版本 python -c "import torch; print(torch.__version__, torch.version.cuda, torch.cuda.is_available())" # 实际加载的驱动 cat /proc/driver/nvidia/version ``` 对应关系: | CUDA 版本 | 最低驱动 | | ------- | ---- | | 12.4 | 550 | | 12.1 | 530 | | 11.8 | 520 | | 11.4 | 470 | 注意几个容易混的点: ```text torch.version.cuda → 编译 PyTorch 时用的 CUDA 版本 nvidia-smi 右上角的 CUDA → 驱动最高能支持的 CUDA 版本 ``` **nvidia-smi 显示的 CUDA 版本比 torch.version.cuda 高是正常的**,不用管。 反过来说,如果 `torch.cuda.is_available()` 返回 False,PyTorch 自己带的 CUDA 库 和驱动不兼容才是问题。 常见报错: ```text "CUDA driver version is insufficient for CUDA runtime version" → 驱动太老,升级驱动 "CUDA error: no kernel image is available for execution on the device" → 驱动不支持这张卡的架构(Ampere / Hopper / Ada 的 sm_xx) → 升级驱动到支持该卡的版本,老驱动不认新卡 "undefined symbol: cudaGetDriverEntryPoint" → 装了多个 CUDA toolkit,环境变量指向了旧的 ``` 多 CUDA 版本共存时,看当前用的是哪个: ```bash echo $CUDA_HOME ls -la /usr/local/ | grep cuda which nvcc && nvcc --version ``` ### 3\. 显存占用异常 / OOM ```bash # 当前每张卡的占用 nvidia-smi --query-gpu=index,name,memory.total,memory.used,memory.free,utilization.gpu \ --format=csv # 找出占显存的进程 nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv # 僵尸进程占用(进程已死但显存没释放) fuser -v /dev/nvidia* ``` 典型情况: **显存被僵尸进程占住** 进程被 kill -9 了,但 CUDA context 没释放: ```bash # 找到占用的进程 nvidia-smi --query-compute-apps=pid --format=csv,noheader # 确认是僵尸(状态 Z) ps -o pid,stat,cmd -p # 清理 kill -9 ``` 如果杀不掉,说明 GPU 卡住了,只能重启: ```bash nvidia-smi --gpu-reset -i 0 # 报 "in use" 就只能重启机器 ``` **训练中途 OOM,但之前能跑** ```bash # 看是不是有其他进程抢了显存 nvidia-smi # PyTorch 显存碎片 python -c "import torch; torch.cuda.empty_cache()" # 混合精度没开 # 在代码里加: # with torch.autocast('cuda', dtype=torch.float16): ``` **设置显存占用比例**(限制 PyTorch 抢多少): ```bash export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True # 老版本用: export PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:128 ``` ### 4\. 训练中断 / "GPU has fallen off the bus" 这个报错最吓人,但通常不是卡坏了。 ```bash # 内核日志里的 Xid dmesg -T | grep -iE "xid|nvidia" | tail -50 # 常见 Xid 码 # Xid 13/31 → 显存错误,可能卡坏了或过热 # Xid 48 → 双位错误,通常要换卡 # Xid 63/64 → 掉卡,PCIe 链路问题 # Xid 79 → GPU 掉卡(硬件故障) ``` 先看物理连接: ```bash # PCIe 链路状态和速率 nvidia-smi -q | grep -A 10 "GPU Link Info" # Link Gen 和 Link Width 都要和安装时一致 # 实际协商到的速率(应为 PCIe 4.0 x16 之类) nvidia-smi --query-gpu=pci.bus_id,pcie.link.gen.current,pcie.link.width.current \ --format=csv ``` **如果协商速率降了**(比如装在 x8 槽位上只能跑 x8,或者速率从 4 降到 1), 说明 PCIe 链路协商有问题,检查主板插槽和转接卡。 处理顺序: ```bash # 1. 查温度(过热也会掉卡) nvidia-smi --query-gpu=index,temperature.gpu,power.draw,power.limit,clocks_throttle_reasons.active \ --format=csv # 2. 查电源线(8 pin / 12VHPWR 没插紧很常见) # 需要去机房看 # 3. 复位 GPU nvidia-smi --gpu-reset -i 0 # 4. 换槽位测试(能换机器上的另一个槽位最好) ``` **电源线没插紧**是掉卡的头号原因。12VHPWR 接头插一半特别容易, 而且接口会发热变色,插的时候要完全到底。 ### 5\. 温度报警 / 降频 ```bash # 详细温度 nvidia-smi --query-gpu=index,name,temperature.gpu,temperature.memory,\ power.draw,power.limit,clocks.sm,clocks.max.sm --format=csv # 降频原因(0=正常,非 0 就是被限制) nvidia-smi --query-gpu=index,clocks_throttle_reasons.active,\ clocks_throttle_reasons.sw_thermal_slowdown,\ clocks_throttle_reasons.hw_thermal_slowdown,\ clocks_throttle_reasons.sw_power_cap,\ clocks_throttle_reasons.hw_power_brake_slowdown --format=csv ``` 常见原因和对策: | 现象 | 原因 | 处理 | | --- | --- | --- | | 温度 85℃+ 一直降频 | 风道堵了 / 风扇转速不够 | 清灰,检查机箱进风口 | | 温度正常但功耗被限 | 电源功率不够 | 核对电源瓦数,升级电源 | | 瞬时温度冲到 95℃ | 散热硅脂老化 | 换硅脂 | | 温度传感器报错 | 卡或固件问题 | 查固件版本 | **数据中心卡(A100/H100)一般是被动散热**,靠机箱风扇吹。这类卡 装在普通塔式机箱里温度一定高,装之前先确认机箱风道。 ### 6\. 推理结果不对 / 精度问题 ```bash # 看是不是掉到了低精度 nvidia-smi --query-gpu=index,name,clocks.sm,clocks.max.sm,power.draw --format=csv ``` ```python # 检查浮点控制状态 import torch print(torch.cuda.get_device_capability(0)) print(torch.backends.cuda.matmul.allow_tf32) print(torch.backends.cudnn.allow_tf32) ``` 几个常见的「结果不对」: **TF32 导致的精度差异** A100/H100 默认开 TF32,矩阵乘法精度从 FP32 降到 TF32。 和 CPU 对数或者做精度回归测试时会对不上: ```python torch.backends.cuda.matmul.allow_tf32 = False torch.backends.cudnn.allow_tf32 = False ``` **多卡结果不一致** ```bash # 检查各卡状态 nvidia-smi --query-gpu=index,name,persistence_mode,compute_mode --format=csv ``` `compute_mode` 应该是 `Default`。如果是 `Exclusive Process`,第二个进程就起不来。 **DDP 通信卡住** ```bash # 看 NCCL 状态 echo $NCCL_DEBUG export NCCL_DEBUG=INFO export NCCL_P2P_DISABLE=1 # 排查 P2P 问题 export NCCL_IB_DISABLE=1 # 排查 InfiniBand 问题 ``` NCCL 卡住通常是 PCIe 拓扑问题: ```bash nvidia-smi topo -m ``` 看同一组卡是不是挂在同一个 CPU socket 下(NVLink 有效), 跨 socket 的 P2P 通信会慢很多甚至卡死。 **显存没对齐导致跑满** ```python # 批大小不是所有卡的倍数 if batch_size % world_size != 0: batch_size = (batch_size // world_size) * world_size ``` ### 7\. 多卡训练 NCCL 挂掉 ```bash # 常见报错 # "NCCL error: unhandled system error" # "NCCL WARN Call to ibv_open_device failed" # "NCCL INFO Bootstrap : no socket interface found" ``` 排查: ```bash # 1. 网卡状态(多机训练必查) ibstat ip addr show | grep ib # 2. 端口和防火墙 ss -lntp | grep -E "29[0-9]{3}" # 3. 关掉一些高级特性先跑通 export NCCL_P2P_DISABLE=1 export NCCL_SHM_DISABLE=1 export NCCL_IB_DISABLE=1 export NCCL_SOCKET_IFNAME=eth0 export NCCL_DEBUG=INFO ``` **`NCCL_SOCKET_IFNAME` 一定要显式指定**,否则多网卡机器上它可能选到 IB 网卡或者管理网口,bootstrap 就连不上。 单机能跑、多机不行,基本都是 IB 网卡或防火墙的问题。 ### 8\. 容器里用不了 GPU ```bash # 容器里跑 docker run --gpus all nvidia/cuda:12.1.0-base-ubuntu22.04 nvidia-smi ``` 报错和对策: ```text "could not select device driver "" with capabilities: [[gpu]]" → 没装 nvidia-container-toolkit → 装完要 systemctl restart docker "unknown option --gpus"(老版本 docker) → docker 19.03 以下不支持,装个新版本 容器里 nvidia-smi 报 "Failed to initialize NVML" → 通常是宿主机驱动版本和容器内 CUDA 版本不匹配 → 容器 CUDA 版本别超过宿主机驱动支持的版本 ``` 装 toolkit: ```bash # Ubuntu distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \ sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg curl -s -L https://nvidia.github.io/libnvidia-container/stable/$distribution/nvidia-container-toolkit.list | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt update && sudo apt install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker ``` ### 9\. 其他常见问题 **MPS 用了之后卡住** ```bash # 启动 MPS nvidia-cuda-mps-control -d # 停掉 echo quit | nvidia-cuda-mps-control # 残留的 MPS 进程要手动清理 ps aux | grep mps ``` **nvidia-smi 显示 "GPU is lost"** ```bash # 软复位 nvidia-smi --gpu-reset -i 0 # 不行就硬复位 sudo nvidia-smi --gpu-reset -i 0 ``` **ECC 报错** ```bash nvidia-smi -q | grep -A 5 "ECC Errors" ``` H100/A100 的 ECC 计数涨了不一定坏,看 `Volatile` 和 `Aggregate` 两项, `Aggregate` 持续涨说明显存真有问题。 **持久化模式没开** 计算节点建议开着,容器和长时间任务启动更快: ```bash nvidia-smi -pm 1 # 做成开机自启 cat > /etc/systemd/system/nvidia-persistenced.service <<'EOF' [Unit] Description=NVIDIA Persisted Daemon After=network.target [Service] Type=forking ExecStart=/usr/bin/nvidia-smi -pm 1 ExecStop=/usr/bin/nvidia-smi -pm 0 [Install] WantedBy=multi-user.target EOF systemctl enable --now nvidia-persistenced ``` ## 验证 ```bash # 基础检查 nvidia-smi # 能看到所有卡,温度功耗正常 nvidia-smi --query-gpu=index,name,driver_version,memory.total,temperature.gpu \ --format=csv # 负载测试 python -c " import torch print('可用:', torch.cuda.is_available()) print('卡数:', torch.cuda.device_count()) for i in range(torch.cuda.device_count()): print(i, torch.cuda.get_device_name(i)) x = torch.randn(4096, 4096, device='cuda') print('矩阵运算 OK:', (x @ x).sum().item()) " # 显存能正常释放(跑完再查一次) nvidia-smi --query-gpu=index,memory.used --format=csv ``` 多卡环境还要确认: ```bash nvidia-smi topo -m # PCIe 拓扑正常 ibstat # IB 网卡正常(多机训练) python -c " import torch, torch.distributed as dist dist.init_process_group('nccl') print('NCCL 正常') " ``` ## 回滚 * **换驱动前先备份旧版本**: ```bash # 记下当前版本 nvidia-smi --query-gpu=driver_version --format=csv,noheader # 旧驱动安装包留着,别删 ``` * **驱动装坏了先别急着重装**,先试软复位: ```bash sudo nvidia-smi --gpu-reset -i 0 ``` * **内核升级前确认 DKMS 能编译**: ```bash # 确认 dkms 装好了 dkms status # 内核头文件在不在 ls /usr/src/kernels/$(uname -r) ``` 内核升级后驱动模块没了,就是 DKMS 没装或头文件不对。 * **固件升级(VBIOS)不可逆**,升级前用 `nvidia-smi -q | grep -i vbios` 记下版本, 确认有备份工具(NVFlash)再动手。 * 温度问题降级处理:临时限制功耗上限,比换硬件快。 ```bash nvidia-smi -pl 200 # 限制到 200W ``` ## 坑 * **`nvidia-smi` 显示的 CUDA 版本是驱动上限,不是实际用的版本**,别照着它装 toolkit。 * **`torch.version.cuda` 和 `nvidia-smi` 的 CUDA 版本不一样是正常的**。 * **驱动升级完不重启内核不生效**,模块还在内存里,得重启。 * **12VHPWR 电源线没插紧是掉卡头号原因**,而且接口会发热变色,要插到底。 * **数据中心卡是被动散热**,装塔式机箱里必热。 * **装完卡要在 BIOS 里开 Above 4G Decoding 和 ReBAR**,否则性能打折甚至不识别。 * **`nvidia-smi --gpu-reset` 在有进程占用时会失败**,先清干净再复位。 * **多机训练不指定 `NCCL_SOCKET_IFNAME` 很可能 bootstrap 失败**。 * **TensorRT 缓存对不上驱动版本**,换驱动后清缓存:`rm -rf ~/.cache/torch`。 * **别在有 checkpoint 之前就反复重试训练**,卡反复掉可能损坏 checkpoint 文件。 * **ECC 报错别忽略**,Volatile 涨可以清,Aggregate 涨就得换卡了。 * **国产卡(华为昇腾、寒武纪等)的 CUDA 生态不一样**,这套命令大多不通用, 得看厂商自己的工具链。