接口监控解决的是链路层问题:端口是否 up、流量是否高、错包丢包是否增长。但网络设备还有另一类风险:风扇停转、电源模块异常、温度过高、CPU 飙升、内存不足、光模块异常。这些问题不一定马上表现为端口 down,却可能是设备故障的前兆。
SNMP 硬件监控比接口监控更复杂,因为不同厂商、不同型号、不同系统版本暴露的 OID 差异很大。本文给出一套可落地的方法:先用通用 MIB 找设备实体和传感器,再针对厂商私有 OID 补齐风扇、电源、温度、CPU、内存等关键指标。
核心要点
- 硬件监控没有绝对通用模板,应先用
snmpwalk确认目标设备真实支持哪些 OID。 - 通用入口优先看 ENTITY-MIB 和 ENTITY-SENSOR-MIB,它们能发现实体、模块、传感器和部分状态。
- 厂商私有 OID 必须配合设备型号、系统版本和 MIB 文档验证,不要照搬其他设备的 OID。
- 状态类指标要先搞清楚枚举值含义,例如
1是否代表 normal,不同厂商可能不同。 - 字符串状态、百分比、带单位数值可以用
conversion和convert_rule转成可告警的数字。 - 硬件指标采集频率通常不需要和接口流量一样高,60 秒到 300 秒更常见。
- 告警要区分“硬件模块异常”和“设备不可达”,SNMP 不通时不要把所有硬件指标缺失都当成硬件故障。
1. 硬件监控应该覆盖什么
网络设备硬件监控通常关注这些对象:
| 对象 | 典型指标 | 告警含义 |
|---|---|---|
| 风扇 | 状态、转速 | 风扇停转、转速异常 |
| 电源 | 在位、状态、输入/输出功率 | 电源模块故障、单电源运行 |
| 温度 | 传感器温度、阈值 | 设备过热、机房散热异常 |
| CPU | 使用率、控制平面负载 | 路由震荡、控制面异常、SNMP 进程压力 |
| 内存 | 使用率、空闲内存 | 控制面内存压力、泄漏风险 |
| 板卡/模块 | 在位、运行状态 | 线卡异常、模块离线 |
| 光模块 | 收发光功率、温度、电压 | 光衰、模块故障、链路隐患 |
第一篇硬件监控不要试图覆盖所有对象。建议先从风扇、电源、温度、CPU、内存开始,光模块可以单独成篇,因为它涉及更多厂商差异和阈值语义。
2. 先用通用 MIB 做发现
很多网络设备支持 ENTITY-MIB。先验证实体表:
snmpwalk -v2c -c '<COMMUNITY>' 10.10.10.11 1.3.6.1.2.1.47.1.1.1.1.2
snmpwalk -v2c -c '<COMMUNITY>' 10.10.10.11 1.3.6.1.2.1.47.1.1.1.1.5
snmpwalk -v2c -c '<COMMUNITY>' 10.10.10.11 1.3.6.1.2.1.47.1.1.1.1.7
这三项分别是:
entPhysicalDescr:实体描述;entPhysicalClass:实体类别;entPhysicalName:实体名称。
常见 ENTITY-MIB OID:
| 字段 | OID | 说明 |
|---|---|---|
entPhysicalDescr |
1.3.6.1.2.1.47.1.1.1.1.2 |
实体描述 |
entPhysicalContainedIn |
1.3.6.1.2.1.47.1.1.1.1.4 |
父实体索引 |
entPhysicalClass |
1.3.6.1.2.1.47.1.1.1.1.5 |
实体类别 |
entPhysicalName |
1.3.6.1.2.1.47.1.1.1.1.7 |
实体名称 |
entPhysicalSerialNum |
1.3.6.1.2.1.47.1.1.1.1.11 |
序列号 |
entPhysicalMfgName |
1.3.6.1.2.1.47.1.1.1.1.12 |
厂商 |
entPhysicalModelName |
1.3.6.1.2.1.47.1.1.1.1.13 |
型号 |
entPhysicalIsFRU |
1.3.6.1.2.1.47.1.1.1.1.16 |
是否现场可替换单元 |
这些指标更适合做资产和标签,不一定直接告警。
3. 传感器优先看 ENTITY-SENSOR-MIB
如果设备支持 ENTITY-SENSOR-MIB,可以继续验证:
snmpwalk -v2c -c '<COMMUNITY>' 10.10.10.11 1.3.6.1.2.1.99.1.1.1
常见字段:
| 字段 | OID | 说明 |
|---|---|---|
entPhySensorType |
1.3.6.1.2.1.99.1.1.1.1 |
传感器类型 |
entPhySensorScale |
1.3.6.1.2.1.99.1.1.1.2 |
数值缩放 |
entPhySensorPrecision |
1.3.6.1.2.1.99.1.1.1.3 |
精度 |
entPhySensorValue |
1.3.6.1.2.1.99.1.1.1.4 |
传感器值 |
entPhySensorOperStatus |
1.3.6.1.2.1.99.1.1.1.5 |
传感器运行状态 |
entPhySensorUnitsDisplay |
1.3.6.1.2.1.99.1.1.1.6 |
单位显示 |
这张表能覆盖一部分温度、电压、电流、功率、风扇转速等指标。但不同设备支持程度差异很大,必须以实际 walk 结果为准。
4. ENTITY-MIB 配置示例
下面是一份实体表配置,主要用于识别硬件模块:
[[instances.table]]
name = "entity"
index_as_tag = true
error_policy = "partial"
filters = [
"A:entPhysicalClass:^(3|5|6|7|8|9|10)$"
]
filters_expression = "A"
filters_mode = "strict"
[[instances.table.field]]
oid = "1.3.6.1.2.1.47.1.1.1.1.2" # entPhysicalDescr
name = "entPhysicalDescr"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.2.1.47.1.1.1.1.5" # entPhysicalClass
name = "entPhysicalClass"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.2.1.47.1.1.1.1.7" # entPhysicalName
name = "entPhysicalName"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.2.1.47.1.1.1.1.11" # entPhysicalSerialNum
name = "entPhysicalSerialNum"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.2.1.47.1.1.1.1.13" # entPhysicalModelName
name = "entPhysicalModelName"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.2.1.47.1.1.1.1.16" # entPhysicalIsFRU
name = "entPhysicalIsFRU"
这里的 entPhysicalClass 是实体类别。不同值代表 chassis、backplane、container、powerSupply、fan、sensor、module、port、stack 等类型。具体枚举以设备 MIB 为准。
这张表本身不一定需要频繁采集,更多是为了给硬件告警提供上下文。
5. ENTITY-SENSOR-MIB 配置示例
传感器表配置:
[[instances.table]]
name = "sensor"
index_as_tag = true
error_policy = "partial"
filters = [
"A:entPhySensorOperStatus:^1$"
]
filters_expression = "A"
filters_mode = "strict"
[[instances.table.field]]
oid = "1.3.6.1.2.1.99.1.1.1.1" # entPhySensorType
name = "entPhySensorType"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.2.1.99.1.1.1.2" # entPhySensorScale
name = "entPhySensorScale"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.2.1.99.1.1.1.3" # entPhySensorPrecision
name = "entPhySensorPrecision"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.2.1.99.1.1.1.4" # entPhySensorValue
name = "entPhySensorValue"
[[instances.table.field]]
oid = "1.3.6.1.2.1.99.1.1.1.5" # entPhySensorOperStatus
name = "entPhySensorOperStatus"
这里有一个重点:entPhySensorValue 的真实单位和缩放要结合 entPhySensorType、entPhySensorScale、entPhySensorPrecision 判断。不要看到值是 45 就直接认为是 45 摄氏度。设备、MIB 和传感器类型不同,解释方式可能不同。
如果目标只是温度告警,很多厂商会提供更直接的私有温度 OID,反而比通用传感器表更容易落地。
6. 厂商私有 OID 怎么找
厂商私有 OID 的路径通常在:
1.3.6.1.4.1.<enterprise>
查找方法有三种。
第一,看厂商 MIB 文档。设备厂商通常会提供 MIB 文件或网管手册,里面有风扇、电源、温度、CPU、内存、光模块等 OID。
第二,用 snmpwalk 从私有企业号下探索:
snmpwalk -v2c -c '<COMMUNITY>' 10.10.10.11 1.3.6.1.4.1
这条命令可能很大,不建议在生产核心设备上随意执行全量 walk。更稳妥的做法是结合厂商 enterprise OID 或文档缩小范围。
第三,从已有监控系统迁移。例如 Zabbix 模板、老的 SNMP exporter 配置、厂商 NMS 系统,都可以作为 OID 来源。但迁移时必须逐条验证,不能直接搬。
每个 OID 至少要确认:
- 它在目标设备上存在;
- 返回值类型是什么;
- 单位是什么;
- 枚举值含义是什么;
- 是否每个型号都支持;
- 是否会带来高基数标签。
7. 风扇监控示例
假设某厂商风扇表有三个字段:
fanName
fanStatus
fanSpeed
配置可以这样写:
[[instances.table]]
name = "fan"
index_as_tag = true
error_policy = "partial"
[[instances.table.field]]
oid = "1.3.6.1.4.1.XXX.1.1.1.1" # fanName
name = "fanName"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.4.1.XXX.1.1.1.2" # fanStatus
name = "fanStatus"
[[instances.table.field]]
oid = "1.3.6.1.4.1.XXX.1.1.1.3" # fanSpeed
name = "fanSpeed"
conversion = "float"
[[instances.table.field.convert_rule]]
match = "offline"
value = -1
告警前要先确认 fanStatus 枚举。例如有些设备 1 是 normal,有些设备可能 1 是 unknown。不要凭经验写:
snmp_fan_fanStatus != 1
应该先用 snmpwalk 和设备页面对照状态,再确定阈值。
风扇转速告警也不能只看绝对值。有些设备支持自动调速,低负载低温时转速低是正常的。更常见的规则是“状态异常”优先于“转速低”。
8. 电源监控示例
电源监控至少关注两个问题:
- 电源模块是否在位;
- 在位电源是否正常。
示例配置:
[[instances.table]]
name = "power"
index_as_tag = true
error_policy = "partial"
[[instances.table.field]]
oid = "1.3.6.1.4.1.XXX.2.1.1.1" # powerName
name = "powerName"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.4.1.XXX.2.1.1.2" # powerPresent
name = "powerPresent"
[[instances.table.field]]
oid = "1.3.6.1.4.1.XXX.2.1.1.3" # powerStatus
name = "powerStatus"
如果设备双电源设计,告警语义要区分:
- 单个电源模块不在位;
- 单个电源模块故障;
- 两个电源都异常;
- 设备只配置单电源,但模板按双电源告警。
不要在不了解硬件设计的情况下,对所有 powerPresent != 1 直接告警。很多接入交换机本来就只有单电源或空电源槽。
9. 温度监控示例
温度指标可以来自通用传感器表,也可以来自厂商私有 OID。
私有 OID 示例:
[[instances.table]]
name = "temperature"
index_as_tag = true
error_policy = "partial"
[[instances.table.field]]
oid = "1.3.6.1.4.1.XXX.3.1.1.1" # temperatureName
name = "temperatureName"
is_tag = true
[[instances.table.field]]
oid = "1.3.6.1.4.1.XXX.3.1.1.2" # temperatureValue
name = "temperatureValue"
conversion = "float"
[[instances.table.field]]
oid = "1.3.6.1.4.1.XXX.3.1.1.3" # temperatureStatus
name = "temperatureStatus"
基础 PromQL:
snmp_temperature_temperatureValue
告警可以按设备类型分层:
snmp_temperature_temperatureValue > 70
但固定阈值要谨慎。不同设备、不同传感器位置、不同厂商阈值不同。更稳妥的做法是:
- 优先使用设备返回的温度状态;
- 状态不可用时再使用温度绝对值;
- 核心设备阈值更保守;
- 结合机房温湿度和风扇状态判断。
10. CPU 和内存监控
网络设备的 CPU 和内存通常是厂商私有 OID。即使都是“CPU 使用率”,也可能存在不同语义:
- 1 分钟、5 分钟、5 秒平均值;
- 控制平面 CPU;
- 每个板卡 CPU;
- 每个核心 CPU;
- 主控板 CPU。
示例:
[[instances.field]]
oid = "1.3.6.1.4.1.XXX.4.1.0" # cpuUsage
name = "cpu_usage"
conversion = "float"
[[instances.field]]
oid = "1.3.6.1.4.1.XXX.4.2.0" # memoryUsage
name = "memory_usage"
conversion = "float"
输出指标:
snmp_cpu_usage
snmp_memory_usage
告警建议:
snmp_cpu_usage > 80
snmp_memory_usage > 85
但不要只看 CPU 高就判断设备故障。网络设备 CPU 高可能来自:
- 路由震荡;
- ARP 或广播风暴;
- SNMP walk 太重;
- 控制平面被攻击;
- 管理登录或配置变更;
- 设备本身 bug。
排障时应结合接口流量、错误包、日志、路由协议状态和设备告警一起看。
11. convert_rule 处理异常字符串
厂商私有 OID 经常返回字符串。比如正常返回:
45 C
异常返回:
unavailable
可以用规则提取:
[[instances.table.field]]
oid = "1.3.6.1.4.1.XXX.3.1.1.2"
name = "temperatureValue"
conversion = "float"
[[instances.table.field.convert_rule]]
match = "unavailable"
value = -1
[[instances.table.field.convert_rule]]
regex = "^([0-9.]+) C$"
extract = "$1"
conversion = "float"
这样:
unavailable转成-1;45 C提取为45;- 其他值回退到默认
conversion = "float"。
状态类字符串也可以转换:
[[instances.table.field.convert_rule]]
match = "normal"
value = 1
[[instances.table.field.convert_rule]]
match = "warning"
value = 2
[[instances.table.field.convert_rule]]
match = "critical"
value = 3
转换后的数字更适合 PromQL 告警。
12. 采集频率和性能
硬件指标变化通常比接口流量慢。建议:
| 指标类型 | 建议采集间隔 |
|---|---|
| 设备可用性 | 30s - 60s |
| 接口流量 | 15s - 60s |
| 风扇、电源、温度 | 60s - 300s |
| CPU、内存 | 30s - 120s |
| 资产信息 | 300s 或更低频 |
如果把 ENTITY-MIB、ENTITY-SENSOR-MIB、接口表、光模块表和多个厂商私有表都放在 15 秒采集周期里,老设备很容易压力过大。
更好的做法是拆分实例:
[[instances]]
# 高频接口监控
# interval_times = 1
[[instances]]
# 低频硬件监控
# interval_times = 4
具体能否用实例级采集周期,要结合全局 interval 和当前部署配置。核心原则是:硬件类指标不必跟接口流量同频。
13. 告警建议
风扇状态异常
snmp_fan_fanStatus != 1
前提是已经确认该设备 1 表示正常。
电源状态异常
snmp_power_powerStatus != 1
建议结合 powerPresent,避免空槽误报。
温度过高
snmp_temperature_temperatureValue > 70
阈值要按设备和传感器位置调整。
CPU 持续高
snmp_cpu_usage > 80
建议持续 5 到 10 分钟再告警,避免短时管理操作造成噪音。
内存使用率高
snmp_memory_usage > 85
如果设备内存长期高但稳定,需要结合厂商建议阈值,不要机械套用服务器经验。
14. 常见问题
为什么同一个 OID 在不同型号上没有值?
厂商私有 OID 常常和型号、系统版本、板卡类型有关。必须按型号验证,不能认为同厂商所有设备都支持。
ENTITY-MIB 能替代厂商私有 OID 吗?
不能完全替代。ENTITY-MIB 适合发现实体和部分传感器,但很多 CPU、内存、风扇、电源细节仍然需要厂商私有 MIB。
状态值怎么确认?
用 snmpwalk 输出、厂商 MIB 文档和设备管理页面三者对照。不要凭别人的模板猜枚举。
字符串能不能直接作为指标值?
Prometheus 风格时序需要数值。字符串更适合作为标签;如果字符串代表状态,应通过 convert_rule 转成数字。
硬件表要不要加 partial?
建议加。硬件私有 OID 更容易出现部分字段不支持或偶发失败。partial 可以避免一个低优先级字段拖垮整张表,但标签和过滤依赖仍然会保守处理。
15. 生产建议
硬件监控要按“通用发现 + 厂商模板”建设。
第一步,用 ENTITY-MIB 和 ENTITY-SENSOR-MIB 了解设备能暴露哪些实体和传感器。
第二步,按厂商和型号整理私有 OID,不同型号不要强行共用一份模板。
第三步,把状态类指标转换成清晰数字,并在文章、配置注释或内部文档里写明枚举含义。
第四步,给硬件指标单独设置采集频率,不要和接口流量同频。
第五步,把硬件告警和设备角色结合起来。核心设备风扇、电源、温度异常应高优先级;普通接入设备可以按持续时间和影响面降噪。
SNMP 硬件监控的价值不是“采到很多厂商 OID”,而是能在设备真正出故障前,把风扇、电源、温度和控制面压力这些早期信号暴露出来。