在 NVIDIA GPU 驱动的诸多疑难杂症中,有一种现象令运维工程师格外头疼:系统运行约两到三个月后,nvidia-smi 命令彻底失去响应,所有基于 NVML 的监控与控制接口全部卡死。GitHub 上的 Issue #971 详细记录了这一问题在 B200 GPU、驱动版本 570.133.20 OpenRM 以及内核 6.6.0 环境下的完整触发过程。深入追踪这条问题链路,可以发现其根源并非 GPU 硬件故障,而是 Linux 内核时间管理与驱动状态轮询机制在特定边界条件下的失效。
现象描述:从正常到永久阻塞的临界点
根据 Issue #971 的描述,受影响系统在连续运行约 66 天 12 小时后,nvidia-smi 命令执行后便陷入无限阻塞,既不返回错误信息也不退出。使用 dmesg 查看内核日志,会发现一系列周期性的 nvlink 告警重复出现,间隔恰好为 4 秒。具体日志如下:NVRM: knvlinkUpdatePostRxDetectLinkMask_IMPL: Failed to update Rx Detect Link mask! 以及 NVRM: knvlinkDiscoverPostRxDetLinks_GH100: Getting peer's postRxDetLinkMask failed!。这些错误以固定频率持续刷屏,表明内核线程仍在运行并尝试执行 NVLink 状态检测,但检测逻辑本身已经陷入异常状态。
值得注意的是,受影响系统的 uptime 显示为 67 天 6 小时,last reboot 记录确认系统自 66 天前启动以来未经历任何重启。这意味着问题的触发与系统运行时间存在明确的数学关联,而非随机偶发的资源竞争或内存泄漏。
核心机制:jiffies 的 32 位溢出边界
理解这一问题的关键在于 Linux 内核的 jiffies 机制。jiffies 是一个全局变量,用于记录系统启动以来经历的时钟中断次数,其值在每次定时器中断时递增。HZ 配置参数定义了每秒产生的时钟中断数量,常见的默认值包括 100 Hz、250 Hz、300 Hz 和 1000 Hz。在 HZ=1000 的配置下,jiffies 每秒增加 1000,32 位无符号整数的最大值为 4294967295,因此理论溢出时间约为 4294967295 除以 1000 再除以 86400,结果约为 49.7 天。
这恰好解释了为何问题在约 50 天后触发,而实际观察到的 66 天时间差异可能源于以下因素:实际 HZ 配置低于 1000、驱动内部存在额外的计时缓冲、或者问题涉及 jiffies_64 与 jiffies 混用时的比较逻辑缺陷。尽管现代 Linux 内核在 64 位架构上主要使用 jiffies_64(64 位变量)来规避溢出问题,但驱动代码中仍可能存在对 32 位 jiffies 的直接比较,尤其是在与用户空间 NVML 库交互的边界层。
阻塞链路:从时间回退检测到 watchdog 触发
当 jiffies 发生溢出时,其值会从最大值瞬间跳回 0。对于依赖时间递增性进行状态检测的代码逻辑,这会产生严重的时间回退(time regression)假象。NVIDIA 驱动内部的 NVLink 状态检测函数(如 knvlinkDiscoverPostRxDetLinks_GH100)可能内置了基于 jiffies 的超时或回退检测机制,用于判断链路状态是否正常。当检测到时间戳回退时,驱动可能将其误判为异常状态,从而触发重试逻辑。
与此同时,Linux 内核的 soft lockup watchdog 机制会监控每个 CPU 核心上是否存在长时间占用调度器的代码。当某个内核线程持续运行超过预设阈值(通常为 20 秒)而未让出 CPU,watchdog 会输出 BUG: soft lockup 错误并尝试干预。如果驱动内部的异常检测逻辑在 jiffies 溢出后陷入死循环,或者在用户空间 NVML 发起查询时内核无法及时响应,watchdog 就会介入并进一步扰乱驱动状态。
nvidia-smi 本身是一个用户空间工具,它通过 NVML 库与内核驱动通信。当驱动内部的轮询机制因上述原因而阻塞时,NVML 的查询请求会一直等待内核响应,从而导致 nvidia-smi 永远挂起。这种阻塞不仅影响 nvidia-smi,所有依赖 NVML 接口的监控组件(如 Prometheus Node Exporter、DCGM、Grafana Loki 等)都会同步失效。
工程影响:生产环境中的隐蔽风险
这一问题的工程影响远不止于 nvidia-smi 命令无法使用。对于运行 AI 训练任务或大规模推理服务的集群,长 uptime 是常态而非例外。GPU 节点通常以周甚至月为单位连续运行,重启操作会中断正在进行的计算任务并导致资源浪费。因此,jiffies 溢出导致的 GPU 管理失效是一个极具隐蔽性的系统性风险。
在受影响系统上,虽然 dmesg 中的 nvlink 告警持续刷屏,但 GPU 核心的计算功能可能仍然正常。驱动并未完全崩溃,只是 NVML 管理接口被阻塞。这种状态会导致调度系统(如 SLURM、Kubernetes)无法获取 GPU 状态信息,可能将已经出现异常的节点继续调度给新任务,或者无法在任务异常时及时执行故障迁移。从监控角度看,GPU 利用率、功耗、温度等指标会突然从可采集变为永久缺失,而这种缺失本身也可能被误判为监控 agent 故障而非 GPU 驱动问题。
应对策略:检测、预防与恢复的工程实践
针对这一问题,生产环境可以从检测、预防和恢复三个层面构建防御体系。在检测层面,最直接的方法是监控系统的 uptime 指标,当其超过 45 天时触发告警。建议在监控系统(如 Prometheus)中设置 uptime > 50 天的告警规则,并配置运维人员及时介入处理。同时,可以定期执行 nvidia-smi --query-gpu=timestamp --format=csv 来验证 NVML 接口的响应性,若超时则视为潜在风险信号。
在预防层面,可以考虑启用 nvidia-persistent 模式。该模式允许 nvidia-smi 在无计算任务运行时保持与驱动的活跃连接,减少 NVML 在空闲时期的休眠行为。此外,定期重启 GPU 监控服务(如 dcgm-exporter、NVIDIA GPU Operator)可以刷新 NVML 会话状态,降低长时间运行累积的风险敞口。对于关键集群,建议制定每月一次的维护窗口计划,在低峰时段执行滚动重启以刷新系统 uptime。
在恢复层面,一旦 nvidia-smi 已被阻塞,最直接的恢复手段是通过重启 GPU 驱动或重启整节点来重置内核状态。对于无法立即重启的生产负载,可以尝试通过 kill -9 终止所有 nvidia-smi 进程并重启 NVML 服务(如果支持热重载),但这通常只能恢复用户空间接口,内核内部的状态仍可能不稳定。因此,最稳妥的恢复策略仍是计划内重启。
架构层面的长期思考
从架构角度看,这一问题暴露出驱动与内核时间子系统交互时的边界处理缺陷。jiffies 溢出是一个已知数十年的边界条件,大多数内核代码已经通过 time_after、time_before 等宏安全封装来处理比较逻辑。然而,NVIDIA 驱动作为闭源或半闭源的内核模块,其内部实现细节对社区不可见,无法像主线内核代码那样接受广泛的代码审查和安全加固。
对于依赖 NVIDIA GPU 的关键基础设施,建议在驱动版本升级时重点关注 Release Notes 中关于 watchdog、timeout、jiffies 相关的修复条目。同时,可以考虑在测试环境中模拟长 uptime 场景(如使用 uptime 注入或时间加速工具)来主动验证驱动稳定性。随着 AMD MI 系列和 Intel Max 系列 GPU 在数据中心的市场份额逐步提升,多供应商 GPU 策略也可以在一定程度上分散这类单点风险。
资料来源
本文核心事实与问题描述参考自 GitHub Issue #971(nvidia-smi hangs indefinitely after ~66 days 12 hours uptime),jiffies 机制原理参考 Oracle Linux 博客关于 Linux Kernel Jiffies 的技术文档。