大促封网期 GPU 平台值守手册:红线看板与 XID 故障快速摘除 Runbook
在大促正式进入封网(Infra Freeze)的值守作战阶段,AI 基础设施团队必须从“建设与压测模式”全面切换至“最高战备值守模式”。在夜间零点流量洪峰过境时,面对上千张处于高负荷运转的 GPU 显卡,值班工程师绝不能临阵慌乱、盲目登录节点排查。值守大屏上必须具备直观的关键红线指标大盘(Red-Line Dashboard),并且每位值班人员的案头都必须备好一份精准、可无脑执行的硬件故障快速摘除应急手册(Runbook)。
当物理机突然爆出 NVIDIA 驱动报错时,值守手册的目标只有一个:在 60 秒内将故障卡或整机安全从在线调度池中剔除,将正在运行的模型负载平滑漂移至热备节点,把对外部用户的感知影响压制到绝对零度。
[大促封网期 GPU 算力平台战备值班拓扑] │ ┌───────────────────────┴───────────────────────┐ ▼ ▼ [战备指挥大屏: 三大红线指标] [应急处置通道: 60秒快速摘除 Runbook] - 1. NVLink / RoCE 通信吞吐丢包率 - 捕获 XID 31 / 48 / 62 / 79 报警 - 2. KV Cache 显存剩余 Block 水位 - 脚本一键执行 GPU Drain + K8s Cordon - 3. 首字延迟 TTFT P99 变化斜率 - 触发在线推理 Pod 毫秒级热备切换 │ │ └───────────────────────┬───────────────────────┘ ▼ [平稳度过大促零点洪峰,零业务中断]值守大屏:三大核心红线指标与阈值
值班人员在值守期间应重点关注以下三项红线指标,一旦触发必须立即介入:
- 红线 1:显存 KV Cache 可用 Block 水位 < 8%
- 物理含义:模型推理引擎的动态显存池已逼近极限,随时可能发生显存 OOM 崩溃;
- 响应动作:立即在前置网关激活长文本限制与自适应丢弃策略。
- 红线 2:NCCL / RoCE 报文重传计数器(
retrans_out_of_buffer)> 10 次/秒- 物理含义:跨机分布式通信网络发生严重微突发丢包或 PFC 拥塞,导致多卡 AllReduce 耗时翻倍;
- 响应动作:立即定位发生丢包的交换机端口与节点,执行慢节点单向隔离。
- 红线 3:出现不可逆驱动报错(XID 48 / 62 / 79)
- 物理含义:物理显卡出现不可纠正 ECC 显存损坏、固件死锁或 PCIe 总线掉卡;
- 响应动作:直接执行以下 Runbook 进行硬件快速摘除。
生产级 XID 故障快速摘除 Runbook
当收到诸如GPU XID 79: GPU fallen off the bus on node-gpu-42的报警时,值班工程师严格按照以下四个步骤操作:
# ============================================================================== # GPU 故障快速隔离应急脚本 (Runbook Step-by-Step) # 适用场景: XID 48 (ECC 坏块) / XID 62 (固件挂死) / XID 79 (掉卡) # ============================================================================== # 步骤 1: 立即将 Kubernetes 节点置为不可调度 (Cordon),阻止新 Pod 分配 NODE_NAME="node-gpu-42" kubectl cordon ${NODE_NAME} # 步骤 2: 为节点打上专用故障污点,强制触发 Kube-Scheduler 规避 kubectl taint node ${NODE_NAME} gpu.infra.status/hardware-fault=true:NoSchedule --overwrite # 步骤 3: 检查该节点上运行的在线推理 Pod 并执行优雅驱逐 (Graceful Evict) # 注意: 设置 30 秒优雅期,让推理引擎处理完当前正在流式输出的最后一个 Token kubectl drain ${NODE_NAME} --ignore-daemonsets --delete-emptydir-data --force --grace-period=30 # 步骤 4: 登录故障物理机 (通过带外管理或 SSH),将显卡置为物理 Drain 模式 # 阻止本地残留进程再次调用 CUDA Context ssh root@${NODE_NAME} "nvidia-smi drain -p 0000:01:00.0 -m 1" echo "【应急隔离完成】节点 ${NODE_NAME} 已成功下线,备用算力池已自动接管!"自动化一键应急隔离 CLI 工具(Go 实现)
为了防止值班人员在深夜紧张敲错命令,我们将上述步骤封装为二进制一键工具:
package main import ( "context" "flag" "fmt" "os" "time" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" ) func main() { nodeName := flag.String("node", "", "故障 GPU 节点名称") flag.Parse() if *nodeName == "" { fmt.Println("错误: 必须指定 -node 参数") os.Exit(1) } config, _ := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG")) clientset, _ := kubernetes.NewForConfig(config) ctx := context.Background() fmt.Printf(">>> [大促应急] 正在执行节点 %s 的毫秒级硬件隔离与驱逐...\n", *nodeName) // 1. Cordon 节点 node, err := clientset.CoreV1().Nodes().Get(ctx, *nodeName, metav1.GetOptions{}) if err != nil { panic(err) } node.Spec.Unschedulable = true // 2. 打上硬性故障污点 node.Spec.Taints = append(node.Spec.Taints, corev1.Taint{ Key: "gpu.infra.status/emergency-drain", Value: "true", Effect: corev1.TaintEffectNoSchedule, }) _, _ = clientset.CoreV1().Nodes().Update(ctx, node, metav1.UpdateOptions{}) // 3. 安全驱逐核心业务 Pod pods, _ := clientset.CoreV1().Pods("").List(ctx, metav1.ListOptions{ FieldSelector: fmt.Sprintf("spec.nodeName=%s", *nodeName), }) var gracePeriod int64 = 20 for _, p := range pods.Items { if p.Namespace == "kube-system" { continue } fmt.Printf(">>> 正在驱逐 Pod: %s/%s\n", p.Namespace, p.Name) _ = clientset.CoreV1().Pods(p.Namespace).Delete(ctx, p.Name, metav1.DeleteOptions{ GracePeriodSeconds: &gracePeriod, }) } fmt.Println(">>> [大促应急] 隔离流程执行完毕,已触发热备实例自动上线!") }封网值班的三条铁律
- 先隔离后排障:大促期间严禁在未隔离节点的情况下直接在生产宿主机上执行
gdb、strace或反复测试重启,必须第一时间将节点摘除,保障大盘稳定; - 严禁在生产集群进行显卡硬复位(Hard Reset):在有多卡通信的 HGX 拓扑中,单卡硬复位可能导致整机 PCIe 链路挂死,必须将整个宿主机平滑 Drain 完毕后通过 IPMI 进行整机冷重启;
- 保持热备池容量恒定:任何一台节点被隔离下线后,值班长必须确认备用池中有一台同规格机器自动顶替,始终维持 10% 以上的算力安全冗余。