在AI基础设施运维领域,oam-tools作为CANN软件栈中的关键组件,其重要性不亚于Linux系统中的sysstat工具集。这个由华为开源的运维工具包,专门针对昇腾(Ascend)AI处理器的运维场景设计,解决了传统运维工具在异构计算环境中的三大痛点:
我在实际运维超过100节点的昇腾集群时发现,使用oam-tools后故障平均修复时间(MTTR)从原来的4小时缩短到30分钟以内。这主要得益于它深度集成了CANN driver的底层接口,能够获取到传统工具无法触及的硬件级数据。
oam-tools虽然作为独立仓库维护,但其功能实现高度依赖CANN driver的以下模块:
| driver模块 | 功能描述 | oam-tools对接组件 |
|---|---|---|
| DCMI接口层 | 提供统一的设备管理API | npu-smi命令行工具 |
| logdrv内核模块 | 实现内核日志到用户态的传递 | log-aggregator服务 |
| bbox故障捕获模块 | 记录硬件异常时的关键上下文 | blackbox-monitor服务 |
| dms设备管理系统 | 管理设备使能/禁用状态 | health-checker服务 |
关键设计原则:oam-tools所有功能都通过driver提供的标准接口访问硬件,绝不直接操作寄存器或内存地址。这种设计既保证了安全性,也确保了工具与不同版本driver的兼容性。
当我们需要检查某台服务器的NPU健康状态时,oam-tools的执行链路如下:
npu-health check命令/dev/davinci_manager设备文件发送ioctl请求这个过程中最关键的npu-smi工具,实际上是driver仓库中sdk_driver/dmc模块的客户端实现。我在排查一个温度告警问题时曾发现,如果直接读取/sys/class/thermal下的数据,其更新延迟可能达到10秒,而通过DCMI接口获取的数据延迟不超过500ms——这正是专业工具的价值所在。
oam-tools的健康检查覆盖了NPU设备的六个核心维度:
芯片基础状态
计算单元状态
内存子系统
互联总线
电源管理
容器化指标(仅限共享模式)
oam-tools中的健康检查核心逻辑位于health_checker/npu_diag.py,其主要流程如下:
python复制class NPUHealthChecker:
def __init__(self, dev_id):
self.dev_id = dev_id
self.sysfs_root = f"/sys/class/davinci/davinci{dev_id}"
def check_power_status(self):
with open(f"{self.sysfs_root}/power_state", 'r') as f:
state = f.read().strip()
if state != "ACTIVE":
raise NPUError(f"Power state abnormal: {state}")
def check_temperature(self):
with open(f"{self.sysfs_root}/thermal_zone/temp", 'r') as f:
temp = int(f.read()) / 1000 # 转换为摄氏度
if temp > 95:
self._trigger_cooling() # 调用驱动散热控制接口
return "CRITICAL"
elif temp > 85:
return "WARNING"
return "NORMAL"
def full_check(self):
report = {
"timestamp": datetime.now().isoformat(),
"device_id": self.dev_id,
"checks": {
"power": self.check_power_status(),
"temperature": self.check_temperature(),
# 其他检查项...
}
}
return report
实际生产环境中,我们通常会结合如下优化策略:
oam-tools需要处理三类异构日志源,每类都需要特殊处理:
| 日志类型 | 采集方式 | 处理难点 | 解决方案 |
|---|---|---|---|
| 内核日志 | 轮询/proc/kmsg或syslog | 高频日志可能丢失 | 内存缓冲+速率限制 |
| 黑匣子日志 | 监控/sys/class/davinci/bbox | 一次性读取特性 | 触发式采集+立即备份 |
| 用户态日志 | 文件监控(inotify) | 日志格式不统一 | 正则解析+结构化转换 |
对于最关键的blackbox日志,其采集过程包含三个关键步骤:
原始日志经过如下处理流程变为结构化数据:
code复制原始日志 → 格式识别 → 字段提取 → 上下文增强 → 存储
以常见的TS超时错误为例,最终生成的日志结构包含:
json复制{
"event_id": "TS_TIMEOUT_0x1A2B",
"severity": "CRITICAL",
"timestamp": "2026-03-15T14:22:33.456Z",
"device": {
"id": 3,
"chip_type": "910B",
"firmware": "1.3.2"
},
"task_context": {
"stream_id": 112,
"task_id": "0x7f8a12c0",
"program_counter": "0x1000abcd",
"error_code": "0x1A2B"
},
"environment": {
"driver_version": "5.0.RC1",
"container_id": "abcd1234"
},
"raw_data": "..." // 保留原始信息用于深度分析
}
这种结构化处理使得我们可以:
在device-share模式下,单个NPU可能被多个容器共享。oam-tools通过以下方式实现精细监控:
进程级资源追踪:
bash复制# 查询某设备上所有容器的NPU内存使用
npu-smi info -t process -i 0 -m
输出示例:
code复制+-----+---------+---------------------+---------------+
| PID | CONTAIN | PROCESS_NAME | MEM_USAGE(MB) |
+-----+---------+---------------------+---------------+
| 123 | abcd123 | python train.py | 2048 |
| 456 | efgh456 | torchrun --nproc 4 | 4096 |
+-----+---------+---------------------+---------------+
容器感知的日志标记:
driver的logdrv模块会主动注入容器上下文:
c复制// driver内核模块中的日志处理代码片段
void log_with_container_ctx(const char *msg) {
struct task_struct *task = current;
char container_id[64] = {0};
get_container_id(task, container_id, sizeof(container_id));
printk("[NPU_DRV][%s] %s", container_id, msg);
}
某次线上训练任务出现内存持续增长问题,通过oam-tools的容器化监控功能,我们快速定位到:
检查各容器内存趋势:
python复制# oam-tools脚本示例
df = pd.DataFrame(log_analyzer.get_container_mem_stats())
plt.plot(df['timestamp'], df['mem_usage'], label=df['container_id'])
发现某个容器的内存呈阶梯式增长
关联该容器的内核日志:
bash复制npu-log analyze --container abcd123 --type kernel --grep "memory"
发现大量HBM分配失败的警告
最终定位到是用户代码中未释放的中间结果张量
根据我们在多个超算中心的部署经验,推荐以下配置:
内核参数调整:
bash复制# 增加日志缓冲区大小
echo "kernel.printk_ratelimit=5" >> /etc/sysctl.conf
echo "kernel.printk_ratelimit_burst=100" >> /etc/sysctl.conf
# 提升sysfs响应速度
echo "vm.dirty_ratio=10" >> /etc/sysctl.conf
oam-tools服务化部署:
systemd复制# /etc/systemd/system/oam-collector.service
[Unit]
Description=oam-tools Data Collector
After=network.target
[Service]
ExecStart=/opt/cann/oam-tools/bin/collector --config /etc/cann/oam.conf
Restart=always
MemoryLimit=1G
CPUQuota=30%
[Install]
WantedBy=multi-user.target
对于关键业务集群,建议采用以下架构:
code复制 +-----------------+
| 中央日志集群 |
| (Elasticsearch) |
+--------+--------+
^
| 异地容灾同步
+------------------+ +------+------+ +------------------+
| 计算节点1 | | 本地日志聚合 | | 计算节点N |
| +--------------+ | | +----------+ | | +--------------+ |
| | oam-collector|----->| | logstash | |---->| |oam-collector| |
| +--------------+ | | +----------+ | | +--------------+ |
+------------------+ +--------------+ +------------------+
关键设计点:
| 错误码 | 可能原因 | 解决方案 |
|---|---|---|
| NPU-1001 | 驱动未加载 | 检查dkms状态并重新安装驱动 |
| NPU-2003 | PCIe链路训练失败 | 检查金手指或更换插槽 |
| NPU-3012 | HBM ECC错误超过阈值 | 降低内存频率或申请更换芯片 |
| NPU-4008 | 容器内存超限 | 调整docker --npu-mem参数 |
| NPU-5005 | 固件版本不匹配 | 升级驱动或回滚固件 |
案例:设备突然从npu-smi中消失
初步检查:
bash复制lspci | grep -i davinci
dmesg | grep -i npu
如果PCI设备存在但驱动未识别:
bash复制# 重新探测设备
echo 1 > /sys/bus/pci/rescan
# 手动绑定驱动
echo "0000:3b:00.0" > /sys/bus/pci/drivers/davinci/bind
检查driver日志:
bash复制npu-log analyze --type driver --level ERR --last 30m
如果发现"MMIO timeout"错误:
bash复制npu-smi set -t pcie -i 0 -c Gen3
在大规模集群中,日志采集可能成为性能瓶颈。我们通过以下方式优化:
批量化处理:
python复制# 原始方式(每条日志单独发送)
for log in logs:
send_to_es(log)
# 优化后(批量发送)
from elasticsearch.helpers import bulk
bulk(es_client, prepare_logs_for_bulk(logs))
实测吞吐量从200条/秒提升至5000条/秒
智能采样策略:
yaml复制# oam-tools配置示例
logging:
sampling_rules:
- pattern: ".*INFO.*"
rate: 0.1 # 仅采集10%的INFO日志
- pattern: ".*ERROR.*"
rate: 1.0 # 全量采集ERROR
根据负载类型调整检查间隔:
| 场景 | 推荐间隔 | 检查重点 |
|---|---|---|
| 训练任务 | 30秒 | 温度、HBM使用率、ECC错误 |
| 推理服务 | 5分钟 | PCIe状态、内存泄漏 |
| 空闲状态 | 10分钟 | 基础电源状态 |
| 升级维护期间 | 5秒 | 固件状态、寄存器一致性 |
配置示例:
bash复制# 对训练节点启用强化监控
npu-monitor config --interval 30 --metrics temp,hbm,ecc
oam-tools支持通过插件机制扩展功能,开发步骤:
创建Python包结构:
code复制custom_checks/
├── __init__.py
├── check_my_feature.py
└── config.yaml
实现检查逻辑:
python复制# check_my_feature.py
from oam.checker import BaseCheck
class MyFeatureCheck(BaseCheck):
name = "my_feature"
def execute(self, device_id):
# 通过sysfs或npu-smi获取数据
value = self.read_sysfs(f"/sys/class/davinci/davinci{device_id}/my_feature")
return {"status": "OK" if value < 100 else "WARNING", "value": value}
注册插件:
yaml复制# config.yaml
plugins:
custom_checks.check_my_feature.MyFeatureCheck:
enabled: true
interval: 60
通过Webhook实现告警通知的示例:
python复制import requests
from oam.alarm import AlarmHandler
class MyAlerter(AlarmHandler):
def handle(self, alarm):
payload = {
"event": "NPU_ALARM",
"severity": alarm.level,
"device": alarm.device_id,
"message": alarm.message,
"timestamp": alarm.timestamp
}
requests.post("https://my-aiops-system/api/alerts",
json=payload,
timeout=3)
在配置中启用:
yaml复制alarm:
handlers:
- custom_handlers.MyAlerter:
endpoint: "https://my-aiops-system/api/alerts"
在升级oam-tools或CANN driver时,需要特别注意:
兼容性检查:
bash复制# 查看版本依赖关系
npu-tool info --compatibility
回滚方案验证:
bash复制tar czf /backup/oam-config-$(date +%s).tar.gz /etc/cann/
灰度发布策略:
我在一次driver升级中曾遇到日志格式变更导致解析失败的问题,后来通过以下方式平滑过渡:
python复制# 在新旧版本兼容的日志解析器
def parse_log_line(line):
try:
return _new_parser(line)
except Exception:
return _legacy_parser(line) # 回退到旧解析逻辑
经过在多个超算中心的部署验证,我们总结了以下黄金准则:
监控策略:
日志管理:
自动化运维:
容量规划:
以下是我们某生产集群使用oam-tools前后的关键指标对比:
| 指标 | 优化前 | 优化后 | 提升幅度 |
|---|---|---|---|
| 故障发现时间 | 15-30分钟 | <1分钟 | 30倍 |
| 日志分析耗时 | 2小时/次 | 5分钟/次 | 24倍 |
| 硬件利用率 | 65% | 82% | +17% |
| 运维人力投入 | 5人/百卡 | 2人/百卡 | 60%↓ |
这些提升主要来自:
根据CANN社区的roadmap,oam-tools将在以下方面持续增强:
智能预测:
深度集成:
可视化增强:
安全加固:
这些新特性将继续巩固oam-tools作为AI基础设施运维标准工具的地位。