记录基于 SNMP 协议采集设备数据时遇到的各种坑。
SNMP
是基于 UDP
的请求-响应方式的协议,服务端(agent)是常见的各种设备,客户端(network management station)向 agent 请求该设备上的数据。数据中心各设备使用的通信协议中,除 MODBUS
外,SNMP
占比最多。
从网络上看,相比 MODBUS RTU
,SNMP
不要求采集器与设备直接连接;从工具上看,相比于仅可运行在 Windows
平台的 Modbus Poll
,snmpget
在 linux/mac
可以很方便地安装运行,在 Windows
上也有编译好的二进制版本。因此 SNMP
的调试非常方便。
由于厂商实现参差不齐,通过 SNMP
请求采集器的数据时,也会出现各种问题。
OID 缺失
在请求中,变量绑定(variable-binding
) 指定了 10 个 oid: p1, p2, ..., p10
,响应中只有 9 个 oid ——p1, p2, ..., p9
,不是 p10
为 nosuch*
等错误数据,而是压根没有,整个响应数据中都不存在 p10
。
因此,在请求数据时,不能假设响应报文与请求报文中的 oid 一一对应——甚至响应 oid 与请求 oid 的个数都不能保证一致,于是,在解析响应数据时,使用 map 保存中间结果会比较方便。
OID 不存在
响应中的某个 oid 在 agent 中不存在,可能是请求了错误的 oid,也可能是 agent 的配置错误,等等。这些情况下,该 oid 在响应中可能的值包括但不限于:NoSuchObject
, NoSuchInstance
, Null
。
IP 不一致
正常情况下,向 IP A 发送请求,响应报文的源 IP 也是 A,但实际中也会出现向 IP A 请求数据,发送响应的却是 IP B。
程序能否正常收到响应,取决于使用的 snmp 库能否处理这种情况,若使用 github.com/gonsmp/gosnmp
,需要指定 UseUnconnectedUDPSocket
为 true
才能兼容这种情况。
另外,如果响应的源 IP 与请求的目的 IP 不一致,k8s 设置的网络策略会对发自 Pod 的 IP 包进行 SNAT,因此在 Pod 中无法收到响应——尽管节点收到了来自 IP B 的响应报文,但由于 IP 不一致,内核无法反向 SNAT,响应报文的目的 IP(节点 IP)无法转换为真正的目的 IP(Pod IP)。
响应超时
agent 性能不足
当请求 oid 个数比较多时,可能出现该情况,需要 agent 优化性能或者降低请求频率与 oid 个数。
agent bug
请求 n-1 和 n+1 个 oid 时都能正常收到响应,但请求 n 个 oid 时无法收到。
这种情况可能的原因是 n 个 oid 的响应报文长度落在了一个特定范围,agent 恰巧无法发送长度在特定范围的报文。