Categraf SNMP 交换机接口监控实战:端口流量、状态、错包和部分采集

本文介绍如何使用 Categraf SNMP 插件监控交换机和路由器接口,覆盖 SNMP 连通性验证、IF-MIB 核心 OID、端口流量、带宽利用率、端口状态、错包丢包、端口过滤、partial 表格采集和告警建议。

作者 快猫星云

SNMP 监控难,不是因为配置文件有多长,而是因为很多人一开始就卡在几个问题上:交换机到底应该采哪些 OID?端口流量应该用 32 位计数器还是 64 位计数器?ifDescrifNameifAlias 哪个适合做标签?为什么某个端口字段采集失败后整张表都没有了?Dashboard 上看到流量之后,又该怎么判断带宽、错包和端口状态是否异常?

Categraf 的 snmp 插件可以主动拉取交换机、路由器、防火墙、负载均衡等支持 SNMP 的设备指标。本文先从最常见的网络设备接口监控开始,围绕 IF-MIB 建立一套可直接复用的配置和 PromQL。后续文章再继续展开 SNMP 表格采集、SNMPv3、厂商私有 OID 和排障。

核心要点

  • 交换机接口监控优先采 IF-MIB / IF-MIB::ifXTable 中的通用指标,不要一开始就陷入厂商私有 MIB。
  • 高速端口优先使用 ifHCInOctetsifHCOutOctets 这类 64 位计数器;ifInOctetsifOutOctets 在高速链路上容易回绕。
  • 端口身份建议同时保留 indexifIndexifNameifDescrifAlias 可以用来展示业务含义,但要控制命名规范。
  • 生产环境不要无脑采集所有端口,应使用 filters 过滤空口、虚拟口、无意义接口,避免时序数量膨胀。
  • 新版 SNMP 插件支持 partial 表格采集策略,可以在部分非关键数值字段失败时保留已成功采集的数据,同时对标签、过滤字段等依赖保持保守处理。
  • SNMP Dashboard 没有绝对通用版本,文章中的 PromQL 以本文配置生成的 snmp_interface_* 指标为准。

1. 交换机接口监控要回答什么

交换机接口监控最少要回答六类问题。

第一,设备是否还能访问:

snmp_up
snmp_icmp_up

snmp_up 表示 Categraf 能否通过 SNMP 读取设备;snmp_icmp_up 表示 ICMP 探测是否可达。二者不完全等价。SNMP 失败可能是 community、SNMPv3 认证、ACL 或 UDP 161 被拦;ICMP 失败可能只是设备禁 ping。

第二,设备是否重启过:

snmp_uptime

sysUpTime 通常是 TimeTicks,单位是百分之一秒。换算成天:

snmp_uptime / 8640000

第三,端口现在是 up 还是 down:

snmp_interface_ifAdminStatus
snmp_interface_ifOperStatus

ifAdminStatus = 1 表示管理状态开启,ifOperStatus = 1 表示运行状态 up。值班时最关心的是“管理状态开启但运行状态 down”的端口。

第四,端口流量和带宽利用率:

rate(snmp_interface_ifHCInOctets[5m]) * 8
rate(snmp_interface_ifHCOutOctets[5m]) * 8

ifHCInOctets / ifHCOutOctets 是字节计数器,乘以 8 后得到 bps。

第五,端口有没有错包和丢包:

rate(snmp_interface_ifInErrors[5m])
rate(snmp_interface_ifOutErrors[5m])
rate(snmp_interface_ifInDiscards[5m])
rate(snmp_interface_ifOutDiscards[5m])

第六,这个端口到底接了什么业务。仅靠 10.1.2.3 Gi1/0/48 很难排障,最好通过 ifAlias 或外部 CMDB 标签让告警里带上业务含义。

2. 写配置前先用 snmpwalk 验证

不要一上来就改 Categraf。先在 Categraf 所在机器上确认 SNMP 本身可用。

SNMPv2c 示例:

snmpwalk -v2c -c '<COMMUNITY>' 10.10.10.11 1.3.6.1.2.1.1.5.0
snmpwalk -v2c -c '<COMMUNITY>' 10.10.10.11 1.3.6.1.2.1.1.3.0
snmpwalk -v2c -c '<COMMUNITY>' 10.10.10.11 1.3.6.1.2.1.31.1.1.1.1

这三条分别验证:

  • sysName.0:设备名;
  • sysUpTime.0:设备运行时间;
  • ifName:接口名称列表。

如果这些命令都超时,先排查网络、设备 ACL、community、SNMP 服务开关和 UDP 161。Categraf 不能绕过 SNMP 协议本身的问题。

如果环境有 MIB,可以使用可读名称:

snmpwalk -v2c -c '<COMMUNITY>' 10.10.10.11 IF-MIB::ifName

如果没有 MIB,直接使用数字 OID 更稳。本文配置也尽量使用数字 OID,减少对本机 MIB 文件的依赖。

3. 最小可用配置

SNMP 插件配置文件通常位于:

conf/input.snmp/snmp.toml

下面是一份面向交换机接口监控的配置。生产环境请替换设备地址、community 和标签。

[[instances]]
agents = [
  "udp://10.10.10.11:161",
  "udp://10.10.10.12:161"
]

timeout = "5s"
retries = 2
version = 2
community = "<COMMUNITY>"
agent_host_tag = "ident"
labels = { region = "cn-east", device_role = "switch" }

# 新版 SNMP 插件支持。旧版本不识别这些配置时,需要先升级或删除。
default_table_error_policy = "partial"
dependency_cache_ttl = "10m"
dependency_cache_max_entries = 10000

# 健康检查参数。异常设备会按 recovery_interval 做恢复探测。
health_check_interval = "60s"
health_check_timeout = "5s"
max_fail_count = 3
recovery_interval = "5m"

[[instances.field]]
oid = "1.3.6.1.2.1.1.3.0" # sysUpTime.0
name = "uptime"

[[instances.field]]
oid = "1.3.6.1.2.1.1.5.0" # sysName.0
name = "source"
is_tag = true

[[instances.table]]
name = "interface"
inherit_tags = ["source"]
index_as_tag = true
error_policy = "partial"

# 先按需过滤。首次接入时可以注释 filters,确认全量端口后再收敛。
filters = [
  "A:ifOperStatus:^(1|2)$",
  "B:ifDescr:^(GigabitEthernet|Ten-GigabitEthernet|TwentyFiveGigE|FortyGigE|HundredGigE|Eth|ge-|xe-|te-)",
  "C:ifAlias:.+"
]
filters_expression = "A && (B || C)"
filters_mode = "strict"

[[instances.table.field]]
oid = "1.3.6.1.2.1.2.2.1.1" # ifIndex
name = "ifIndex"
is_tag = true

[[instances.table.field]]
oid = "1.3.6.1.2.1.2.2.1.2" # ifDescr
name = "ifDescr"
is_tag = true

[[instances.table.field]]
oid = "1.3.6.1.2.1.31.1.1.1.1" # ifName
name = "ifName"
is_tag = true

[[instances.table.field]]
oid = "1.3.6.1.2.1.31.1.1.1.18" # ifAlias
name = "ifAlias"
is_tag = true

[[instances.table.field]]
oid = "1.3.6.1.2.1.2.2.1.7" # ifAdminStatus
name = "ifAdminStatus"

[[instances.table.field]]
oid = "1.3.6.1.2.1.2.2.1.8" # ifOperStatus
name = "ifOperStatus"

[[instances.table.field]]
oid = "1.3.6.1.2.1.31.1.1.1.15" # ifHighSpeed, Mbps
name = "ifHighSpeed"

[[instances.table.field]]
oid = "1.3.6.1.2.1.31.1.1.1.6" # ifHCInOctets
name = "ifHCInOctets"

[[instances.table.field]]
oid = "1.3.6.1.2.1.31.1.1.1.10" # ifHCOutOctets
name = "ifHCOutOctets"

[[instances.table.field]]
oid = "1.3.6.1.2.1.2.2.1.13" # ifInDiscards
name = "ifInDiscards"

[[instances.table.field]]
oid = "1.3.6.1.2.1.2.2.1.14" # ifInErrors
name = "ifInErrors"

[[instances.table.field]]
oid = "1.3.6.1.2.1.2.2.1.19" # ifOutDiscards
name = "ifOutDiscards"

[[instances.table.field]]
oid = "1.3.6.1.2.1.2.2.1.20" # ifOutErrors
name = "ifOutErrors"

这份配置会产生类似下面的指标名:

snmp_up
snmp_icmp_up
snmp_icmp_rtt
snmp_uptime
snmp_interface_ifAdminStatus
snmp_interface_ifOperStatus
snmp_interface_ifHighSpeed
snmp_interface_ifHCInOctets
snmp_interface_ifHCOutOctets
snmp_interface_ifInErrors
snmp_interface_ifOutErrors
snmp_interface_ifInDiscards
snmp_interface_ifOutDiscards

其中 sourceindexifIndexifDescrifNameifAliasidentregiondevice_role 会作为标签参与查询和告警。

4. 配置项怎么理解

agents 是设备地址。建议显式写协议和端口,例如 udp://10.10.10.11:161。如果省略协议,默认使用 UDP。

versioncommunity 用于 SNMPv2c。SNMPv3 的认证加密配置会在后续文章单独展开。生产网络如果安全要求较高,优先使用 SNMPv3。

agent_host_tag = "ident" 表示把设备地址写入 ident 标签。这样 Dashboard 和告警可以按设备过滤。若团队已有统一标签规范,也可以使用 agent_hostdeviceinstance,但要和 Dashboard 查询保持一致。

labels 适合放稳定标签,例如区域、机房、设备角色、环境。不要把接口描述、工单号、临时用途放在实例级标签里。

default_table_error_policy = "partial" 是新版能力。历史行为是 legacy:表格里任一字段失败,当前表可能整体失败。partial 会保留已成功采到的数值字段,但对影响行身份和标签正确性的依赖仍然保守处理,例如 tag 字段、filter 字段、secondary index 和继承标签未知时不会盲目上报。

dependency_cache_ttl 是 partial 模式下的依赖缓存时间。它只缓存标签、过滤字段、secondary-index 映射和顶层继承标签这类依赖值,用于应对短暂读取失败。不要把 TTL 设置得过长,否则设备端口标签发生变化后,旧标签可能保留更久。

5. 为什么优先采这些 OID

下面这组 OID 是交换机接口监控的基础集合。

指标 OID 用途
sysName.0 1.3.6.1.2.1.1.5.0 设备名,适合作为继承标签
sysUpTime.0 1.3.6.1.2.1.1.3.0 设备运行时间,判断重启
ifIndex 1.3.6.1.2.1.2.2.1.1 接口索引,端口行身份
ifDescr 1.3.6.1.2.1.2.2.1.2 接口描述,常见如 GigabitEthernet1/0/1
ifName 1.3.6.1.2.1.31.1.1.1.1 接口名称,通常更短更适合展示
ifAlias 1.3.6.1.2.1.31.1.1.1.18 接口别名,适合写业务用途
ifAdminStatus 1.3.6.1.2.1.2.2.1.7 管理状态
ifOperStatus 1.3.6.1.2.1.2.2.1.8 运行状态
ifHighSpeed 1.3.6.1.2.1.31.1.1.1.15 接口带宽,单位 Mbps
ifHCInOctets 1.3.6.1.2.1.31.1.1.1.6 64 位入方向字节计数器
ifHCOutOctets 1.3.6.1.2.1.31.1.1.1.10 64 位出方向字节计数器
ifInErrors 1.3.6.1.2.1.2.2.1.14 入方向错包
ifOutErrors 1.3.6.1.2.1.2.2.1.20 出方向错包
ifInDiscards 1.3.6.1.2.1.2.2.1.13 入方向丢弃
ifOutDiscards 1.3.6.1.2.1.2.2.1.19 出方向丢弃

很多设备还支持 ifInOctetsifOutOctets,但它们是 32 位计数器。百兆以下端口问题不大,千兆、万兆或更高速端口上更容易回绕,建议优先使用 ifHC* 64 位计数器。

ifAlias 很有价值,但也要谨慎。如果团队把工单号、临时备注、人员名字频繁写入端口描述,ifAlias 作为标签会造成时序变化。生产环境最好约定稳定格式,例如:

to-core-sw02
to-prod-k8s-node-rack12
to-payment-fw-a

6. 启动和验证

修改配置后,先用测试模式看输出:

./categraf --test --inputs snmp

可以用 rg 过滤关键信息:

./categraf --test --inputs snmp 2>&1 \
  | rg 'snmp_(up|icmp_up|uptime|interface_ifHC|interface_ifOperStatus|interface_ifInErrors|interface_ifOutErrors)'

正常情况下应该能看到:

snmp_up ident=10.10.10.11 1
snmp_uptime ident=10.10.10.11,source=sw-core-01 ...
snmp_interface_ifHCInOctets ident=10.10.10.11,ifName=...
snmp_interface_ifOperStatus ident=10.10.10.11,ifName=...

如果 snmp_up = 0,先回到 snmpwalk 验证。若 snmp_up = 1 但没有接口指标,重点检查:

  • filters 是否过滤掉了所有端口;
  • 设备是否支持 ifHCInOctetsifHCOutOctets
  • Categraf 版本是否支持 default_table_error_policyerror_policydependency_cache_ttl
  • Categraf 日志中是否有 OID 不存在、超时或权限错误。

正式运行后,在后端查询:

snmp_up
snmp_interface_ifOperStatus
snmp_interface_ifHCInOctets

测试模式只证明采集侧能拿到数据,不证明 remote write 已经写入后端。如果后端查不到,请继续检查 writer 地址、网络、队列和后端数据源。

7. PromQL 怎么看端口流量

入方向流量:

sum by (ident, source, ifName, ifAlias) (
  rate(snmp_interface_ifHCInOctets[5m]) * 8
)

出方向流量:

sum by (ident, source, ifName, ifAlias) (
  rate(snmp_interface_ifHCOutOctets[5m]) * 8
)

如果只想看某台设备:

sum by (ifName, ifAlias) (
  rate(snmp_interface_ifHCOutOctets{ident="10.10.10.11"}[5m]) * 8
)

带宽利用率需要结合 ifHighSpeedifHighSpeed 单位是 Mbps,因此要乘以 1000000 转为 bps:

100 *
rate(snmp_interface_ifHCOutOctets[5m]) * 8
/
clamp_min(snmp_interface_ifHighSpeed * 1000000, 1)

入方向同理:

100 *
rate(snmp_interface_ifHCInOctets[5m]) * 8
/
clamp_min(snmp_interface_ifHighSpeed * 1000000, 1)

如果某些设备上 ifHighSpeed = 0 或缺失,带宽利用率就不能直接算,应先修设备侧接口速率,或为这些端口单独补充静态容量标签。

8. PromQL 怎么看端口状态

所有运行状态不是 up 的端口:

snmp_interface_ifOperStatus != 1

真正需要告警的通常不是所有 down 端口,而是“管理状态开启,但运行状态 down”:

snmp_interface_ifAdminStatus == 1
and on (ident, index)
snmp_interface_ifOperStatus != 1

这里使用 index_as_tag = true 生成的 index 标签做向量匹配。如果你的配置没有开启 index_as_tag,可以改用 ifIndex 标签,前提是你把 ifIndex 配成了 is_tag = true

常见状态值可以这样理解:

ifAdminStatus ifOperStatus
1 up up
2 down down
3 testing testing

不同设备可能还有更细状态,告警前应在目标设备上验证实际返回值。

9. PromQL 怎么看错包和丢包

入方向错包速率:

rate(snmp_interface_ifInErrors[5m])

出方向错包速率:

rate(snmp_interface_ifOutErrors[5m])

入方向丢弃速率:

rate(snmp_interface_ifInDiscards[5m])

出方向丢弃速率:

rate(snmp_interface_ifOutDiscards[5m])

可以按接口聚合:

sum by (ident, source, ifName, ifAlias) (
  rate(snmp_interface_ifInErrors[5m])
  + rate(snmp_interface_ifOutErrors[5m])
  + rate(snmp_interface_ifInDiscards[5m])
  + rate(snmp_interface_ifOutDiscards[5m])
)

错包和丢包不要只看一次瞬时尖刺。建议结合 5 到 15 分钟窗口、业务流量和链路角色判断。核心上联、存储网络、跨机房链路上的持续错包更值得关注;普通空闲端口偶发少量错误,优先级可以低一些。

10. 如何过滤端口

SNMP 监控最容易犯的错误是采集所有端口。很多设备会暴露大量 VLAN、Loopback、Null、Tunnel、Stack、管理口、虚拟口和空口,全部采集会带来三个问题:

  • 后端时序数量快速膨胀;
  • Dashboard 变量里出现大量无意义端口;
  • 告警噪音变多,真正关键端口被淹没。

建议按阶段处理。

第一阶段,先不加过滤,运行测试模式确认设备返回了哪些端口:

./categraf --test --inputs snmp 2>&1 \
  | rg 'snmp_interface_if(HCInOctets|OperStatus|InErrors)'

输出里的 ifNameifDescrifAlias 是标签,不是独立指标。检查端口名称时,看这些数值指标后面带的标签即可。

第二阶段,找出接口命名规律。例如核心物理口可能是:

GigabitEthernet1/0/1
Ten-GigabitEthernet1/0/49
HundredGigE1/0/1
ge-0/0/0
xe-0/0/0
Eth-Trunk1

第三阶段,再配置 filters

filters = [
  "A:ifOperStatus:^(1|2)$",
  "B:ifDescr:^(GigabitEthernet|Ten-GigabitEthernet|HundredGigE|Eth|ge-|xe-|te-|Eth-Trunk)",
  "C:ifAlias:.+"
]
filters_expression = "A && (B || C)"
filters_mode = "strict"

这表示:端口状态要是 up 或 down,并且接口描述像物理口,或者配置了非空 ifAlias。实际环境要按厂商命名调整,不要直接照抄正则。

11. partial 表格采集解决什么问题

SNMP 表格采集经常遇到不完整数据。比如某台设备支持 ifDescrifOperStatusifHCInOctets,但不支持 ifAlias;或者某个字段偶发超时。历史行为下,表内任一字段失败可能导致整张表失败,用户看到的结果就是“明明大部分 OID 都能 walk,Dashboard 却没有接口指标”。

新版 SNMP 插件增加了表格错误策略:

default_table_error_policy = "partial"

[[instances.table]]
name = "interface"
error_policy = "partial"

partial 的原则是:保留已经成功采集到的数值字段,但不牺牲标签和行身份正确性。

可以保留的场景:

  • 某个普通数值字段失败,例如 ifOutDiscards 偶发读取失败;
  • 同一行其他数值字段已经成功,例如流量和状态仍然可用。

仍然会保守跳过的场景:

  • tag 字段未知,无法确认这行指标属于哪个端口;
  • filter 字段未知,无法判断这行是否应该被采集;
  • inherited tag 未知,无法继承设备身份;
  • secondary index 依赖未知,可能造成行错配。

这就是所谓 fail closed:宁可少报一部分,也不要报出标签错乱的数据。

如果设备偶发丢字段,可以开启依赖缓存:

dependency_cache_ttl = "10m"
dependency_cache_max_entries = 10000

缓存只保存依赖值,例如 tag、filter 字段、secondary-index 映射和顶层继承标签。它不是把所有指标都缓存起来,也不会用旧流量值冒充新流量值。

12. Dashboard 怎么导入

SNMP 采集内容由用户配置决定,因此不存在完全通用的 Dashboard。Categraf 仓库里提供了一个基础接口大盘:

inputs/snmp/dashboard.json

导入后要重点检查三件事:

  • Dashboard 查询的指标名是否和你的配置一致;
  • 变量使用的标签是否存在,例如 identsourceifName
  • 面板是否使用 64 位计数器和正确单位。

如果使用本文配置,PromQL 应以 snmp_interface_* 为准,例如:

rate(snmp_interface_ifHCInOctets[5m]) * 8
rate(snmp_interface_ifHCOutOctets[5m]) * 8
rate(snmp_interface_ifInErrors[5m]) + rate(snmp_interface_ifOutErrors[5m])

如果导入后没有数据,先不要怀疑采集。直接在后端裸查:

snmp_up
snmp_interface_ifHCInOctets
snmp_interface_ifOperStatus

如果裸指标存在,并且这些指标上能看到 ifNameifDescrifAlias 等标签,问题多半在 Dashboard 的数据源、变量、标签名或 PromQL。

13. 告警建议

设备 SNMP 不可达

snmp_up == 0

建议持续 2 到 3 个采集周期再告警。网络设备 SNMP 偶发超时并不少见,直接按单点失败告警会比较吵。

设备 ICMP 不可达

snmp_icmp_up == 0

如果设备禁 ping,不要配置这条告警,或者关闭 disable_icmp_up 相关采集。

端口管理 up 但运行 down

snmp_interface_ifAdminStatus == 1
and on (ident, index)
snmp_interface_ifOperStatus != 1

这条规则应只对关键端口启用。普通接入口经常因为终端关机而 down,不适合全部告警。

端口带宽利用率过高

100 *
rate(snmp_interface_ifHCOutOctets[5m]) * 8
/
clamp_min(snmp_interface_ifHighSpeed * 1000000, 1)
> 80

建议按链路类型分层:核心上联可以 70% 或 80% 预警,接入口可以更宽松。

端口错包或丢包持续增长

sum by (ident, source, ifName, ifAlias) (
  rate(snmp_interface_ifInErrors[10m])
  + rate(snmp_interface_ifOutErrors[10m])
  + rate(snmp_interface_ifInDiscards[10m])
  + rate(snmp_interface_ifOutDiscards[10m])
) > 0

这条规则不要一刀切。某些端口少量丢包可能来自限速、队列调度或广播控制,应结合端口角色和基线调整阈值。

设备重启

snmp_uptime < 30000

这里的 30000 约等于 300 秒,因为 sysUpTime 是百分之一秒。也可以用 changes(snmp_uptime[10m]) 辅助判断,但不同设备计数行为可能有差异。

14. 常见问题

为什么用 ifHCInOctets,而不是 ifInOctets?

ifInOctets 是 32 位计数器,高速端口上容易快速回绕。ifHCInOctetsifHCOutOctets 是 64 位计数器,更适合千兆、万兆和更高速链路。

ifAlias 可以作为标签吗?

可以,但前提是它相对稳定。ifAlias 很适合写“接到哪台设备、哪个业务、哪条链路”,但如果经常被人临时修改,会导致标签变化和时序漂移。

SNMP up 正常,但接口指标没有数据?

先注释 filters,用测试模式确认接口表是否有数据。再检查设备是否支持 ifHC* OID,以及 Categraf 日志里是否有某个字段 walk 失败。

为什么 partial 后还是有些行被跳过?

partial 不是“任何错误都继续上报”。如果标签、过滤字段、继承标签等依赖未知,Categraf 会跳过相关行,避免输出标签缺失或错配的数据。

Dashboard 里的指标名和文章不一致怎么办?

以实际配置和后端裸指标为准。SNMP 指标名由 inputNametable.namefield.name 共同决定。本文配置下,接口表字段会输出为 snmp_interface_<field>,例如 snmp_interface_ifHCInOctets

15. 生产建议

SNMP 监控要分层建设。

第一层先做可用性:snmp_upsnmp_icmp_upsnmp_uptime。这能快速发现设备不可达、SNMP 权限变化和设备重启。

第二层做接口流量和状态:ifOperStatusifAdminStatusifHighSpeedifHCInOctetsifHCOutOctets。这能覆盖绝大多数交换机端口监控需求。

第三层做质量指标:ifInErrorsifOutErrorsifInDiscardsifOutDiscards。这类指标更适合结合端口角色和历史基线告警。

第四层再做厂商私有硬件指标:温度、风扇、电源、CPU、内存、光模块。不要在第一篇配置里把所有厂商 OID 都混进去,否则配置复杂度会迅速失控。

最后,SNMP 配置一定要和设备命名规范一起治理。没有稳定的设备名、端口名和端口描述,再好的采集器也只能生成一堆难以排障的时间序列。

延伸路径

继续看解决方案和产品对比

如果你正在做监控、可观测性或故障定位相关选型,建议从解决方案和产品对比继续往下看。

快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云