摘要
1、基于 https://github.com/Project-HAMi/ascend-device-plugin/tree/v1.3.0 分析软切分 NPU 的 Device Plugin 代码
2、回答几个问题:
与华为原生的 Device Plugin 有何区别:上报的资源、分配机制?
软切分是如何实现的?简要说明其原理,核心实现在 https://github.com/Project-HAMi/hami-vnpu-core,后续单独讲,本章只讲怎么用的
软切分是如何实现的?简要说明其原理,核心实现在 https://github.com/Project-HAMi/hami-vnpu-core,后续单独讲,本章只讲怎么用的
如何与 HAMi 调度器配合实现软切分
Ascend Device Plugin 代码结构分析
一、项目概述
Ascend Device Plugin是一个 Kubernetes Device Plugin 实现,用于管理华为 Ascend NPU(神经网络处理器)设备的分配与调度。该插件与 HAMi(Hierarchical AI Resource Management)调度器集成,支持 vNPU(虚拟 NPU)的动态创建和资源隔离。
二、目录结构
ascend-device-plugin/ ├── cmd/ # 命令行入口 │ └── main.go # 程序主入口 ├── internal/ # 内部模块 │ ├── manager/ # 设备管理器 │ │ └── manager.go # Ascend设备管理核心逻辑 │ ├── server/ # gRPC服务端 │ │ └── server.go # Device Plugin API实现 │ ├── vnpu.go # 配置结构定义 │ └── watchers.go # 文件系统/信号监视器 ├── libvnpu/ # vNPU 核心库(Rust 实现)都是通过子模块下载下来的:git submodule update --init --recursive,原代码中只有一个目录 │ ├── crates/ # Rust crates │ │ ├── hook/ # Hook模块 │ │ └── limiter/ # 资源限制器 │ └── script/ # 辅助脚本 ├── mind-cluster/ # MindSpore 集群相关组件,都是通过子模块下载下来的:git submodule update --init --recursive,原代码中只有一个目录 │ └── component/ # 各种组件模块 │ ├── ascend-common/ # 公共组件 │ ├── ascend-device-plugin/ # 设备插件(另一实现) │ ├── ascend-docker-runtime/ # Docker运行时 │ ├── ascend-faultdiag/ # 故障诊断 │ ├── ascend-for-volcano/ # Volcano调度器集成 │ └── ascend-operator/ # Kubernetes Operator ├── examples/ # 示例配置 │ ├── ascendjob-310p.yaml │ └── ascendjob-910b.yaml ├── go.mod/go.sum # Go依赖管理 └── Dockerfile/Makefile # 构建配置三、核心模块职责
| 模块 | 文件 | 职责 |
|---|---|---|
| cmd | main.go | 程序入口,参数解析,初始化流程控制 |
| manager | manager.go | 设备发现、健康检查、vNPU生命周期管理 |
| server | server.go | gRPC服务,Device Plugin API实现,HAMi集成 |
| internal | vnpu.go | 配置结构定义与 YAML 加载 |
| internal | watchers.go | 文件系统与信号监听工具 |
| internal | watchers.go | 文件系统和信号监听工具 |
四、核心组件详解
4.1 主入口 (cmd/main.go)
职责:程序初始化和主循环控制
核心流程:
- 参数解析:解析命令行参数(配置文件、节点名称等)
- 日志初始化:配置华为日志和klog
- 设备管理器创建:初始化底层设备管理接口
- 配置加载:加载全局配置和节点特定配置
- 服务启动:启动gRPC服务并进入主循环
- 事件监听:监听文件系统事件和系统信号
关键代码路径:
main() → checkFlags() → NewAscendManager() → LoadConfig() → NewPluginServer() → start()命令行参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--config_file | string | 空 | 配置文件路径(必需) |
--node_name | string | NODE_NAME环境变量 | 节点名称(必需) |
--node_config_file | string | 空 | 节点特定配置文件路径 |
--hw_loglevel | int | 0 | 华为日志级别 |
--check_idle_vnpu_interval | int | 60 | 检查空闲vNPU间隔(秒) |
4.2 设备管理器 (internal/manager/manager.go)
职责:管理物理NPU设备和vNPU的生命周期
核心数据结构:
typeDevicestruct{UUIDstring// 设备唯一标识LogicIDint32// 逻辑设备IDPhyIDint32// 物理设备IDCardIDint32// 卡IDDeviceIDint32// 设备IDMemoryint64// 内存大小(字节)AICoreint32// AI Core数量Healthbool// 健康状态(true表示健康)}typeAscendManagerstruct{mu sync.RWMutex// 读写锁mgr*devmanager.DeviceManager// 底层设备管理器config internal.VNPUConfig// vNPU配置globalConfig internal.Config// 全局配置devs[]*Device// 设备列表nodeConfig*internal.NodeConfig// 节点配置}关键方法:
| 方法 | 功能 |
|---|---|
NewAscendManager() | 创建设备管理器实例 |
LoadConfig(path) | 加载设备配置文件 |
LoadNodeConfig(nodePath, nodeName) | 加载节点特定配置 |
UpdateDevice() | 更新设备列表 |
GetDevices() | 获取设备列表(线程安全) |
GetDeviceByUUID(UUID) | 根据UUID查找设备 |
GetUnHealthIDs() | 获取不健康设备ID列表 |
CleanupIdleVNPUs() | 清理空闲vNPU |
VDeviceCount() | 计算单个物理设备可虚拟出的vNPU数量 |
4.3 gRPC服务端 (internal/server/server.go)
职责:实现Kubernetes Device Plugin API,与Kubelet和HAMi调度器交互
实现的Device Plugin API:
| API方法 | 功能 |
|---|---|
ListAndWatch | 列出设备并监听状态变化 |
Allocate | 为Pod分配设备 |
GetDevicePluginOptions | 获取插件选项 |
PreStartContainer | 容器启动前处理 |
核心数据结构:
typePluginServerstruct{commonWordstring// 设备通用标识词nodeNamestring// 节点名称grpcServer*grpc.Server// gRPC服务实例mgr*manager.AscendManager// 设备管理器socketstring// Unix socket路径stopChchaninterface{}// 停止信号通道healthChchanint32// 健康状态变更通道checkIdleVNPUIntervalint// 检查空闲vNPU的间隔}HAMi集成功能:
- 设备注册:向HAMi调度器注册设备信息
- 节点注解更新:更新节点注解以支持调度决策
- vNPU核心模式:支持HAMi vNPU Core模式的资源隔离
vNPU Core模式挂载:
当Pod使用huawei.com/vnpu-mode: hami-core注解时,会注入:
- 驱动挂载:华为NPU驱动和SMI工具链(只读)
- 库注入:通过
/etc/ld.so.preload注入HAMi运行时库 - 共享内存:挂载共享内存区域用于资源协调
- 环境变量:设置
NPU_MEM_QUOTA、NPU_PRIORITY等
4.4 配置模块 (internal/vnpu.go)
核心配置结构:
typeTemplatestruct{Namestring`json:"name"`// 模板名称Memoryint64`json:"memory"`// 内存大小(字节)AICoreint32`json:"aiCore"`// AI Core数量}typeVNPUConfigstruct{CommonWordstring// 通用标识词(如Ascend910)ChipNamestring// 芯片名称ResourceNamestring// Kubernetes资源名称MemoryAllocatableint64// 可分配内存大小MemoryCapacityint64// 总内存容量AICoreint32// AI Core总数Templates[]Template// 可用的vNPU模板列表}typeConfigstruct{VNPUsstruct{HamiVnpuCorebool// 是否启用HAMi vNPU核心模式Configs[]VNPUConfig// 各芯片型号的配置列表}}五、数据流和交互关系
┌─────────────────────────────────────────────────────────────────────┐ │ Kubernetes Cluster │ ├─────────────────────────────────────────────────────────────────────┤ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ HAMi │ │ Kubelet │ │ Device │ │ │ │ Scheduler │◄───────│ │───────►│ Plugin │ │ │ │ │ │ │ │ │ │ │ └──────────────┘ └──────────────┘ └──────┬───────┘ │ │ │ │ │ │ │ 1. 注册设备信息 │ │ │ │ 2. 获取待分配设备 │ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Node │ │ Pod │ │ Ascend │ │ │ │ Annotations │ │ Annotations │ │ Manager │ │ │ │ │ │ │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ Ascend Device Plugin │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │ main │───►│ server │───►│ manager │───►│ DCMI │ │ │ │ │ │入口控制 │ │ gRPC服务│ │设备管理 │ │底层接口 │ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘六、关键设计特点
6.1 vNPU虚拟化支持
- 支持将物理NPU划分为多个vNPU
- 通过模板配置不同规格的vNPU(内存、AI Core数量)
- 自动清理空闲vNPU释放资源
6.2 健康监控机制
- 定期检查设备健康状态
- 发现不健康设备时自动更新设备列表
- 通知Kubelet设备状态变化
6.3 HAMi集成
- 通过节点注解与HAMi调度器交互
- 支持vNPU Core模式的细粒度资源隔离
- 使用共享内存区域实现容器间资源协调
6.4 容错机制
- gRPC服务崩溃自动重启(最多5次/小时)
- 监听Kubelet socket重建事件自动重新注册
- 优雅处理系统信号实现安全退出
6.5 启动流程
Start() ├─► prepareHostResources() // 准备宿主机资源 ├─► mgr.UpdateDevice() // 更新设备列表 ├─► serve() // 启动gRPC服务 ├─► registerKubelet() // 向Kubelet注册 ├─► startPeriodicCheckIdleVNPUs() // 定期检查空闲vNPU └─► watchAndRegister() // 监听并向HAMi注册七、配置示例
7.1 全局配置文件
vnpus:hamiVnpuCore:trueconfigs:-commonWord:"Ascend910"chipName:"Ascend910B"resourceName:"huawei.com/Ascend910"resourceMemoryName:"huawei.com/Ascend910-memory"memoryAllocatable:32212254720# 30GBmemoryCapacity:34359738368# 32GBaiCore:64aiCPU:8templates:-name:"30GB"memory:32212254720aiCore:64-name:"15GB"memory:16106127360aiCore:32-commonWord:"Ascend310P"chipName:"Ascend310P"resourceName:"huawei.com/Ascend310P"memoryAllocatable:8053063680# 7.5GBmemoryCapacity:8589934592# 8GBaiCore:4templates:-name:"7.5GB"memory:8053063680aiCore:47.2 节点配置文件
nodes:-name:"node-gpu-01"hami-vnpu-core:truevDeviceCount:4-name:"node-gpu-02"hami-vnpu-core:falsevDeviceCount:2八、运行方式
# 基本运行命令./ascend-device-plugin\--config_file=/path/to/config.yaml\--node_name=$(NODE_NAME)\--check_idle_vnpu_interval=60# 完整参数./ascend-device-plugin\--config_file=/etc/ascend-device-plugin/config.yaml\--node_name=node-01\--node_config_file=/etc/ascend-device-plugin/node-config.yaml\--hw_loglevel=0\--check_idle_vnpu_interval=60\--report_time_offset=1九、环境变量
| 环境变量 | 说明 |
|---|---|
NODE_NAME | 节点名称(可替代--node_name参数) |
HAMI_VNPU_ASSETS_PATH | vNPU核心库资源路径 |
十、总结
Ascend Device Plugin 是一个架构清晰、功能完备的 Kubernetes Device Plugin 实现,具有以下特点:
- 分层架构:职责分离,模块间解耦
- 高可用设计:支持故障自动恢复和优雅重启
- 灵活配置:支持全局配置和节点级配置
- 深度集成:与HAMi调度器无缝集成,支持vNPU虚拟化
- 可扩展性:支持多种Ascend芯片型号
该插件为在Kubernetes集群中高效管理和调度华为Ascend NPU资源提供了完整的解决方案。
vnpu架构:
下面是软切分(vNPU)从物理设备到容器内虚拟设备的核心流程:
hami-vnpu-core 的角色:它是一个用 Rust 实现的运行时库,通过LD_PRELOAD机制注入到容器中。其hook模块负责拦截应用对 NPU 驱动(如libascendcl.so)的调用,根据共享内存中的配额信息动态限制内存和算力使用;limiter模块则负责在超出配额时进行降速或拒绝,从而实现真正的资源隔离与软切分。