症状:nvidia-smi 翻车现场
上周三凌晨 2 点,我们训练集群的 PagerDuty 炸了——所有 GPU 节点报错:
Failed to initialize NVML: Driver/library version mismatch
nvidia-smi 直接罢工,但 NVIDIA 驱动模块 (nvidia.ko) 明明还活着。更坑的是,lsmod | grep nvidia 显示驱动还在,而 nvidia-smi 却像吃了闭门羹。
这种场景,我一年踩了不下 5 次。每次都是 apt upgrade 或无人值守更新后静默升级了 nvidia-kernel-dkms 或 libnvidia-compute-*,但内核模块没跟着重编。结果就是:驱动模块(内核态)和库文件(用户态)版本脱节。
根本原因:谁动了我的驱动?
说白了,就两种可能:
- 包管理器自动升级:Ubuntu/Debian 的
unattended-upgrades偷偷把nvidia-*包升了,但没触发dkms重编内核模块。这是最常见的情况,尤其是你开着安全更新自动安装时。 - 手动安装冲突:你之前用
.run文件装了驱动,后来用apt又装了一遍,或者反过来。两套安装路径互相打架。
我见过最离谱的一次是,有人跑了 apt install nvidia-driver-550,但系统里残留着 545 的 .run 安装残留。结果 nvidia-smi 调用了新库,但内核模块还是旧的。
修复步骤:不重启版
注意:下面这套方案不需要重启。如果你能重启,那 reboot 是最省心的。但生产环境、远程机器、或者你只是懒,可以试试这个。
Step 1: 确认版本差距到底多大
先别急着操作,跑一下这些命令看看真实状态:
# 查看当前加载的内核模块版本
cat /proc/driver/nvidia/version
# 查看用户态库版本
dpkg -l | grep nvidia
# 或者用这个
nvidia-smi --version
对比一下。如果内核模块版本(比如 550.90.07)和库版本(比如 550.120)对不上,那就确认是 mismatch 了。
Step 2: 杀光残留进程(关键!)
内核模块加载后,如果有进程还在用旧版本的库,nvidia-smi 会一直报错。我们需要把这些进程都干掉。
# 找出所有使用 NVIDIA 库的进程
sudo lsof /dev/nvidia*
# 或者用这个更暴力的
sudo fuser -v /dev/nvidia*
你会看到一堆 python、Xorg、gnome-shell 什么的。手动 kill 它们:
sudo kill -9 <PID>
如果你在用 GPU 跑着训练任务,这一步要小心。建议先停掉任务再操作。
Step 3: 卸载旧内核模块并重新加载
# 卸载当前 nvidia 模块(需要先卸载依赖它的模块,比如 nvidia_uvm, nvidia_drm)
sudo rmmod nvidia_uvm
sudo rmmod nvidia_drm
sudo rmmod nvidia_modeset
sudo rmmod nvidia
# 重新加载(会自动加载新版本)
sudo modprobe nvidia
如果 rmmod 报错说模块正忙,说明你没杀干净进程。回到 Step 2 再检查一遍。
Step 4: 重新生成 initramfs(对付下次重启)
这一步不是必须的,但能防止你重启后又翻车。因为 initramfs 里可能还存着旧的内核模块。
sudo update-initramfs -u
Step 5: 验证
nvidia-smi
如果还报错,那就只能祭出大招了——完全卸载重装。
终极方案:完全重装驱动
如果上面那套不行,或者你想一劳永逸:
# 1. 卸载所有 NVIDIA 包
sudo apt purge -s "nvidia*" "libnvidia*"
# 2. 如果之前用 .run 文件装过,也要卸载
sudo /path/to/NVIDIA-Linux-*.run --uninstall
# 3. 清理残留
sudo apt autoremove
sudo apt autoclean
# 4. 重新安装
sudo apt update
sudo apt install nvidia-driver-550 # 或者你需要的版本
# 5. 重启
sudo reboot
注意:.run 文件和 apt 包管理器不要混用。选定一个方式,就别再换。我个人推荐用 apt,因为更新方便。
对比:不同修复方式的优缺点
| 修复方式 | 需要重启? | 风险等级 | 适用场景 | 成功率 |
|---|---|---|---|---|
| 杀进程 + 重加载模块 | 否 | 中(可能中断任务) | 生产环境、远程机器 | 70% |
| 完全卸载重装 | 是 | 低 | 本地开发机、测试环境 | 95% |
| 锁定版本(apt-mark hold) | 否 | 低 | 预防性措施 | 100%(预防) |
| 手动编译 DKMS | 否 | 高 | 内核升级后的修复 | 80% |
如何预防?锁定版本
吃一堑长一智。我现在所有 GPU 服务器的做法:
# 锁定 nvidia 相关包,不让它们自动升级
sudo apt-mark hold nvidia-driver-550 libnvidia-compute-550 nvidia-kernel-dkms
这样 unattended-upgrades 就不会偷偷升级驱动了。等你想升级的时候,手动 apt-mark unhold 再升。
FAQ
Q: How to fix nvidia graphics driver issue?
A: 先确认是驱动问题还是硬件问题。跑 dmesg | grep nvidia 看内核日志。如果是 mismatch,按上面的步骤来。如果日志里有 NVRM: failed to initialize,大概率是驱动和内核版本不兼容。
Q: How to fix NVIDIA driver not compatible?
A: 不兼容通常发生在内核升级后。比如你升了 Linux 内核到 6.8,但 NVIDIA 驱动 545 不支持。解决方法:要么降级内核,要么升级 NVIDIA 驱动到 550+。也可以用 dkms 强制重编模块:sudo dkms install -m nvidia -v <version>。
Q: How do I fix NVIDIA driver installer error?
A: 常见的 installer error 包括 “You appear to be running an X server”(先关掉图形界面)、“Unable to find the kernel source tree”(安装 linux-headers-$(uname -r))、“CC version check failed”(gcc 版本不对)。用 .run 文件安装时加 --no-opengl-files 可以避免一些冲突。
Q: Has NVIDIA fixed their driver issues?
A: 没有,也不可能完全解决。因为 NVIDIA 驱动是闭源的,内核接口一变就要跟着改。开源驱动 nouveau 倒是稳定,但性能差得远。目前 550 系列算是比较稳的,但 545 和 535 都出过不少幺蛾子。建议用 LTS 内核 + LTS 驱动版本组合。
最后说一句
这个 mismatch 问题,本质上是 Linux 生态里闭源驱动的原罪。NVIDIA 的驱动更新策略一直很拉胯——新版本修了旧 bug,但引入新 bug。我见过有人因为这个问题在 prod 上挂了 3 小时,就因为一个 unattended-upgrades 的默认配置。
所以,我的建议很简单:锁定版本,定期手动更新。别让自动更新替你决定什么时候该升级驱动。尤其是 AI 训练集群,稳定比版本新重要得多。
如果你在 remote 机器上遇到这个问题,又没法重启,上面 Step 2-3 那套组合拳基本能搞定 70% 的情况。剩下的 30%?那就只能远程求助运维同学帮你按电源键了。