如何根据Cluster节点故障自动恢复业务
AI服务器单点硬件故障不可避免,在大规模算力使用场景下,资源池规模越大存在硬件故障的可能性越高。当发生硬件故障时可能会影响节点上服务的正常运行。
Lite Cluster节点巡检到故障后,会上报故障信息到k8s节点和AOM云服务,详情请见Cluster节点故障上报。ModelArts提供故障感知、通知能力,配合业务在原生k8s中进行快速恢复。
针对故障节点信息,自动恢复业务的解决方案大致流程如下:
步骤1:获取故障节点信息(以Watch k8s节点方式为例)
自动恢复业务后,处理故障节点请参见如何定位和处理Cluster资源池节点故障。
如果是GPU资源池会同时安装node-agent组件和gpu device-plugin组件。如果是NPU资源池则是会同时安装node-agent组件和npu device-plugin组件。
节点故障上报如图1所示。
故障感知:device-plugin负责xpu卡的故障巡检,node-agent负责AI运行环境的巡检。 device-plugin组件会从驱动侧获取芯片故障并实时上报可用卡数到K8S NodeAllocatable,同时,对使用NPU卡的k8s Pod,device-plugin会自动为其挂载npu状态文件可用于pod内进行健康检查。node-agent组件则是通过巡检脚本收集各故障信息,同时将检测结果汇聚并写到K8S NodeCondition中。
故障通知:node-agent收集到巡检结果后,会周期性上报节点故障指标到AOM服务,配置及时通知方法可参见如何定位和处理Cluster资源池节点故障
K8S Node Allocatable以及Condition详情可参考Kubernetes节点状态。
K8S NodeCondition样例:
{
"type": "NT_NPU_CARD_LOSE",
"status": "False",
"lastHeartbeatTime": null,
"lastTransitionTime": "2024-09-27T10: 45: 55Z",
"reason": "os_task_name:npu-card-lose",
"message": "ok"
}
status有3种值:False、True以及Unknown。以上述为例,当status为True时,代表节点发生了Type类型为“NT_NPU_CARD_LOSE”的故障,所有故障类型定义请参见如何定位和处理Cluster资源池节点故障。
package main
import (
"context"
"fmt"
"time"
"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() {
// 通常可以使用clientcmd.RecommendedHomeFile,值是$HOME/.kube/config,根据自身情况可以修改
config, _ := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
// 创建 clientset 客户端
clientset, _ := kubernetes.NewForConfig(config)
// 创建一个 watcher
watcher, err := clientset.CoreV1().Nodes().Watch(context.TODO(), metav1.ListOptions{})
if err != nil {
fmt.Printf("Failed to create watcher: %v\n", err)
}
defer watcher.Stop()
termCh := make(chan struct{}, 1)
// 事件驱动获取节点故障信息
go func() {
for {
select {
case <-termCh:
return
case event, ok := <-watcher.ResultChan():
if !ok {
fmt.Printf("Failed to get watcher chan: %v\n", err)
return
}
node := event.Object.(*v1.Node)
fmt.Printf("Event type: %v, Node name: %s\n", event.Type, node.Name)
for _, v := range node.Status.Conditions {
fmt.Printf("Node Condition Type: %v, Type Status: %v\n", v.Type, v.Status)
}
}
}
}()
// 或者全量获取Nodes
nodes, _ := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
fmt.Printf("There are %d nodes in the cluster\n", len(nodes.Items))
time.Sleep(10 * time.Second)
// 定义结束信号
termCh <- struct{}{}
}
当业务为训练作业时,可参考设置断点续训练。



