在数据中心和深度学习工作负载中,GPU 服务器通常需要连续运行数周乃至数月。然而,一个隐蔽但影响严重的问题正在浮出水面:NVIDIA GPU 驱动在运行约 66 天后会出现 nvidia-smi 永久挂起的现象。这一问题不仅影响运维监控,更可能导致关键计算任务中断,造成不可挽回的损失。
问题现象与影响范围
根据 NVIDIA 官方开源 GPU 内核模块项目中的 Issue #971 记录,运行 driver 570.133.20 OpenRM 的 B200 服务器在 uptime 达到约 66 天 12 小时后,nvidia-smi 命令会无限期挂起,无法返回任何 GPU 状态信息。该问题同样出现在 Ubuntu 24.10 环境下使用 560 系列驱动的场景中,表现为运行 nvidia-smi 时系统内存被迅速耗尽,甚至导致整机崩溃需要强制重启。
这一问题的严重性在于其隐蔽性和破坏性。GPU 服务器通常部署在不便频繁重启的环境中,长期运行的计算任务可能持续数周时间。当 nvidia-smi 挂起后,运维人员将无法获取 GPU 温度、显存使用率、计算进程状态等关键监控数据,更无法执行 GPU 重置等恢复操作。对于依赖实时 GPU 监控的生产环境,这意味着失去了对硬件健康状态的感知能力。
从系统日志中可以观察到问题发生时的特征性错误模式。dmesg 输出中频繁出现 NVRM 相关的 nvlink 错误信息,包括 "knvlinkUpdatePostRxDetectLinkMask_IMPL: Failed to update Rx Detect Link mask!" 以及 "knvlinkDiscoverPostRxDetLinks_GH100: Getting peer's postRxDetLinkMask failed!"。这些错误表明问题不仅涉及用户态工具的挂起,更涉及 GPU 驱动核心层的异常状态。
根因分析:32 位计数器溢出假说
约 66 天这一精确时间节点强烈暗示了计数器溢出的可能性。分析 2 的幂次方时间边界:32 位有符号整数最大值为 2147483647,若以毫秒为单位,2^31 毫秒约为 24.8 天,2^32 毫秒约为 49.7 天。若计数器以纳秒为单位工作,则最大可持续时间更长,但考虑到 66 天略超过 49.7 天的两倍,这可能涉及双阶段溢出或特定子系统的 32 位计数器设计。
NVIDIA GPU 驱动内部存在多个依赖于时间累加的子系统。GPU 硬件层面的功耗管理、显存刷新、NVLink 链路状态检测等均使用基于时间的计时器。当这些计时器达到上限后,可能触发异常行为,导致通信通道阻塞。用户态工具 nvidia-smi 通过 NVML 库与内核驱动通信,若内核端的某个等待循环因计数器问题而永久阻塞,整个调用链将失去响应。
此外,nvidia-persistenced 守护进程负责维护 GPU 状态的持久化。该进程通过 Unix 域 socket 与 nvidia-smi 通信,当 socket 权限或进程状态异常时,可能导致通信挂起。社区反馈的临时解决方案 "sudo chmod o-w /var/run/nvidia-persistenced/socket" 正是通过阻止 socket 写入来绕过这一问题,说明持久化机制的某个环节确实存在触发条件。
预防策略与工程实践
针对长期运行场景,建立预防性维护机制是保障 GPU 集群稳定性的关键。第一道防线是定期重启策略,建议将 GPU 服务器的重启周期设置在 40 至 50 天之间,显著早于问题触发时间点。这一策略虽然简单粗暴,但考虑到问题后果的严重性,在 NVIDIA 发布正式修复之前,这是可靠性最高的保障手段。
监控告警的部署应当覆盖问题的早期信号。通过定期执行 nvidia-smi 命令并测量响应时间,可以建立基线数据。当命令执行时间超过正常值数倍时触发告警,预示可能的问题前兆。建议使用毫秒级精度记录每次 nvidia-smi 的执行耗时,当出现渐进式增长趋势时,提前安排维护窗口。
内核参数的调优也能在一定程度上缓解问题。Linux 内核的 nvidia 模块支持通过 modprobe 参数调整初始化行为,例如设置 InitializeSystemMemoryAllocations 和 MemoryPoolSize 等参数来优化内存分配策略。然而,这些参数的具体效果因驱动版本和硬件型号而异,需要在测试环境验证后方可大规模部署。
自动恢复机制设计
当 nvidia-smi 挂起发生时,快速恢复能力决定了业务中断的时长。对于规模化部署,应当建立自动检测与恢复流程。使用独立的 watchdog 进程定期尝试执行简化的 nvidia-smi 查询(如仅获取 GPU 计数),当检测到超时时触发预设的恢复动作。
恢复动作的分级策略应当预先设计。第一级尝试通过 SIGTERM 终止 hung 状态的 nvidia-smi 进程,释放可能持有的资源。第二级尝试重启 nvidia-persistenced 服务,这可以通过 systemctl restart nvidia-persistenced 实现。第三级作为最后手段,执行 GPU 的 PCI 层重置,这需要内核支持且可能需要 root 权限。完整的恢复脚本应当记录每次尝试的结果,便于后续分析问题模式。
对于容器化部署环境,GPU 节点应当具备被调度系统标记为 unhealthy 的能力。Kubernetes 生态中的 node-problem-detector 可以配置为监控 GPU 状态,当检测异常时将节点从可调度池中移除,触发 workload 的自动迁移。这是云原生环境下保障服务可用性的标准实践。
监控指标与健康检查
完善的 GPU 监控体系应当超越简单的温度和利用率指标,涵盖驱动健康状态的多个维度。建议监控以下指标:nvidia-smi 命令执行耗时(建立 P50、P90、P99 百分位基线)、显存分配失败事件频率、NVLink 链路错误计数、GPU ECC 错误累积数。这些指标的异常增长往往先于 nvidia-smi 挂起发生,是有价值的预警信号。
健康检查的实现应当考虑非阻塞设计。避免在主监控循环中直接调用可能挂起的 nvidia-smi,而是采用超时控制和独立进程的方式。超时阈值建议设置为正常执行时间的 5 至 10 倍,对于大多数环境,2 至 3 秒足以覆盖正常变幅。任何超过阈值的执行都应当记录并告警。
日志分析同样是不可或缺的环节。定期扫描 dmesg 和系统日志中的 NVRM 关键字,当错误频率出现增长趋势时触发人工介入。问题发生时的特征性错误模式(如前文所述的 nvlink 相关错误)可以作为自动检测的签名规则。
未来展望与社区跟进
NVIDIA 已在官方渠道确认该问题并创建内部 Bug 编号(NV-Triaged),表明厂商已知晓并着手调查。然而,GPU 驱动的复杂性决定了修复周期不会太短。在此之前,运维团队需要将问题纳入风险评估框架,制定相应的缓解措施。
从长期技术演进角度看,GPU 驱动的可靠性设计需要重新审视。计数器溢出问题在嵌入式系统中是经典教训,但在通用计算环境中往往被忽视。驱动代码应当对所有基于时间的计数器进行充分的边界测试,确保在整数溢出时能够优雅降级而非永久阻塞。用户态工具应当实现更健壮的通信超时和重试机制,避免单点故障影响整体监控能力。
对于依赖 GPU 持续运行的关键业务系统,建议建立与 NVIDIA 官方的直接沟通渠道,及时获取修复进展和临时规避方案。同时,保持驱动版本的适度跟进,在充分测试的基础上及时应用包含问题修复的新版本驱动。
参考资料
- NVIDIA open-gpu-kernel-modules Issue #971: nvidia-smi hangs after ~66 days uptime
- NVIDIA Developer Forums: nvidia-smi memory leak discussions on Ubuntu 24.10