Telegraf 最佳实践:SNMP 插件
作者:Jay Clifford / 用例, 产品, 开发者
2022年6月1日
导航至
Telegraf 现在已拥有 300 多个插件,并部署在各种用例中。一月份,我们发布了一篇博客文章,介绍了创建配置和优化 Telegraf Agent 的黄金法则。现在是时候深入了解社区最常用的一些插件了。
在这篇文章中,我们将介绍 SNMP 输入插件。我与我们的 Telegraf 维护者之一 Thomas Casteleyn (Hipska) 坐下来,讨论他在使用 SNMP 输入插件时的最佳实践。Thomas 是我们 SNMP 插件最多产的用户之一,为他的客户收集来自数千个设备和系统的指标。在他的帮助下,我的目标是为您提供一些有用的技巧和窍门,助您从新手变专家!
什么是 SNMP 输入插件?
如果您正在阅读这篇博客,您可能已经知道 SNMP 是什么,但让我们为所有人统一一下标准。以下是一些事实
- SNMP 代表简单网络管理协议 (Simple Network Management Protocol)。
- 自 1988 年以来就已存在(它经受住了时间的考验,并且不会很快消失)。
- 引入该协议是为了满足监控和管理 IP 设备的需求。
- 示例设备:路由器、交换机、防火墙、负载均衡器、服务器和闭路电视摄像机只是一些例子。
- SNMP 有三个版本(1、2c 和 3)。了解这一点很重要,因为根据制造商和设备的年限,您可能会有混合使用的情况。
- V1 和 2c 使用团体字符串。V3 需要用户名和密码。V3 还提供加密功能。
- 端口:SNMPv3 161, 162 (trap) | SNMPv3 安全端口 10161, 10162 (trap)
如果您想了解更多关于 SNMP 的信息,我强烈建议您观看 CertBros 的这个视频。
在 Telegraf 中,我们有两个基于 SNMP 的插件
- SNMP - 使用轮询从 SNMP Agent 收集指标。它支持收集单个 OID 和整个 SNMP 表。
- SNMP Trap - 服务输入插件,用于接收 traps 和 informs 请求。Samantha Wang 发布了一篇很棒的博客,帮助您开始使用 SNMP Trap 插件。我强烈建议您查看一下,因为我们将介绍 SNMP 插件。
基础知识
让我们从介绍一些基础知识开始。在本例中,我们将使用 Telegraf 从 Windows 10 VM 收集指标
[[inputs.snmp]]
## Agent addresses to retrieve values from.
agents = ["udp://127.0.0.1:161"]
## Timeout for each request.
timeout = "15s"
## SNMP version; can be 1, 2, or 3.
version = 2
## SNMP community string.
community = "public"
## Number of retries to attempt.
retries = 1
[[inputs.snmp.field]]
oid = "SNMPv2-MIB::sysUpTime.0"
name = "uptime"
conversion = "float(2)"
[[inputs.snmp.field]]
oid = "SNMPv2-MIB::sysName.0"
name = "source"
is_tag = true
[[inputs.snmp.table]]
oid = "HOST-RESOURCES-MIB::hrStorageTable"
name = "hrStorageTable"
inherit_tags = ["source"]
完整的 Telegraf 配置可以在这里找到。
让我们分解一下
- agents - 您想要监控的 SNMP Agent(启用 SNMP 的设备)列表。在大多数情况下,您的 Agent 端口将为 161。
- timeout - 我用粗体突出显示它,因为我们稍后会讨论它。此参数告诉 Telegraf 等待 Agent 回复的时间。
- version - 您的 Agent 正在运行的 SNMP 版本。大多数 Windows Agent 默认运行版本 2 (2c)。
- community - 本质上是 SNMP Agent 的密码。在 Windows 中,您可以定义 SNMP 团体字符串。请注意,如果不使用正确的团体字符串,Telegraf 将无法收到来自 Agent 的任何响应。
- retries - 如果请求超时,Telegraf 尝试轮询 Agent 的次数。
现在我们已经设置了初始 SNMP 插件参数,让我们开始从我们的 Agent 请求一些指标。在我们的例子中,我们想知道以下内容
- Agent 的运行时间
- Agent 的名称
- Agent 的存储指标
要获取这些指标,一种方法是直接访问包含值的字段,如下所示
[[inputs.snmp.field]]
oid = "SNMPv2-MIB::sysUpTime.0"
name = "uptime"
conversion = "float(2)"
[[inputs.snmp.field]]
oid = "SNMPv2-MIB::sysName.0"
name = "source"
is_tag = true
在本例中,我们直接引用系统运行时间和系统名称的 OID(对象标识符)。请注意,is_tag 允许我们将返回的值转换为指标标签。运行时间字段的转换是因为运行时间以百分之一秒为单位报告。
我们可用的第二种方法是引用包含我们希望收集的字段的表
[[inputs.snmp.table]]
oid = "HOST-RESOURCES-MIB::hrStorageTable"
name = "hrStorageTable"
inherit_tags = ["source"]
与直接字段引用类似,我们为表指定 OID。然后我们可以为表提供一个测量名称。最后,inherit_tags 允许我们的表采用另一个字段的标签。再次使用系统名称是合理的,它被命名为“source”。
最佳实践、技巧和窍门
好的,现在我们知道 SNMP 是什么,并使用 Telegraf SNMP 插件设置了一个基本示例。这些信息足以让您开始使用,但它可以在规模上进行管理吗?Thomas 给了我一些在构建 Telegraf SNMP 配置时要遵循的很好的规则。在接下来的部分中,我们将把它们分解为您可以直接在 SNMP 插件上采取的操作,以及在使用 处理器插件后对指标采取的操作。
SNMP 插件
字段与表
在可能的情况下,直接指定字段而不是表。在 SNMP 表中,可能存在任意字段(如元数据),这些字段不需要在每个时间间隔进行监控。这可能会使请求通常更慢地返回结果。
在某些情况下,拉取完整的表以节省时间并提高配置可读性是有意义的。值得注意的是,某些设备可能需要长达 1 分钟才能将大型 SNMP 表返回给 Telegraf。您应该确保适当增加您的 timeout 参数。
分而治之
值得为您监控的每个设备创建一个 SNMP 输入插件,而不是将它们分组到一个插件中。
例如
# Local Device
[[inputs.snmp]]
## Agent addresses to retrieve values from.
agents = ["udp://127.0.0.1:161"]
## Timeout for each request.
timeout = "5s"
[[inputs.snmp.table]]
oid = "HOST-RESOURCES-MIB::hrStorageTable"
name = "hrStorageTable"
inherit_tags = ["source"]
# Remote device known to be slow
[[inputs.snmp]]
## Agent addresses to retrieve values from.
agents = ["udp://192.168.1.5:161"]
## Timeout for each request.
timeout = "60s"
[[inputs.snmp.table]]
oid = "HOST-RESOURCES-MIB::hrStorageTable"
name = "hrStorageTable"
inherit_tags = ["source"]
在 SNMP 插件的逻辑中,只有当所有源都返回回复后,才会处理指标。本质上,在这种情况下,您的速度与最慢的 Agent 一样慢。这也意味着,如果一个 Agent 未能在给定的时间内发送回回复,SNMP 插件将进入重试循环(取决于您的配置),这将延迟下一轮收集(对于同一 SNMP 插件的所有 Agent),直到重试循环完成。
分离成单独的插件将 Agent 彼此解耦。这允许首先处理响应时间更快的 Agent,并提高解决方案的整体持久性。由于 Telegraf 的占用空间很小,创建更多插件不会显着增加系统上 Agent 的开销。
有用的元数据
当从多个设备订阅等效字段和表时,能够区分指标以进行进一步处理/查询非常重要。以下是一些您可以包含的重要标签
主要
- 系统名称 (SNMPv2-MIB::sysName.0)
- 主机名
可选
- 位置 (SNMPv2-MIB::sysLocation.0)
- 技术提供商 / 类型
指标与元数据
在 SNMP 表中找到的字段可以有多种用途。有些字段适合长期监控。其他字段将保持静态/线性,除非手动更新或系统发生重大配置;例如,向设备添加更多存储。这取决于您是否决定完全删除这些字段,还是将它们作为标签包含在内以进行过滤。
这方面的一个很好的例子是 ifAdminStatus 与 ifOperStatus
- ifAdminStatus - 接口的期望状态。在大多数情况下,除非重新配置,否则它不会改变(元数据)。
- ifOperStatus - 接口的当前操作状态。这是一个值得监控的字段,因为它将提供 Agent 接口的当前状态(指标)。
处理器插件
现在我们已经很好地掌握了如何配置 SNMP 输入插件,现在是时候分享一些关于我们收集的指标的巧妙后处理方法了。以下是一些配置代码片段,以帮助提高可读性和值转换
接口映射:
上面我们讨论了有用的元数据,如 ifAdminStatus。IfAdminStatus 提供接口的期望状态。一般来说,接口可以置于三种主要状态
- 启用
- 禁用
- 测试中
但是,当我们请求 ifAdminStatus 值时,我们收到的是数值,而不是人类可读的文本。要更改这一点,我们可以使用 Enum 处理器插件:
[[inputs.snmp]]
## Agent addresses to retrieve values from.
agents = ["udp://127.0.0.1:161"]
[[inputs.snmp.field]]
oid = "SNMPv2-MIB::sysName.0"
name = "source"
is_tag = true
[[inputs.snmp.table]]
oid = "IF-MIB::ifTable"
name = "interface"
inherit_tags = ["source"]
[[inputs.snmp.table.field]]
oid = "IF-MIB::ifAdminStatus"
is_tag = true
# Translate tag values for interface table
[[processors.enum]]
namepass = ["interface"]
# Translate IF-MIB::ifAdminStatus
[[processors.enum.mapping]]
## Name of the tag to map
tag = "ifAdminStatus"
## Table of mappings
[processors.enum.mapping.value_mappings]
1 = "up"
2 = "down"
3 = "testing"
完整的 Telegraf 配置可以在这里找到。
如您所见,我们使用 namepass 仅处理名为 interface 的测量。我们查找 IfAdminStatus 标签,然后为包含的值提供新的映射(1 = “up”)。请注意,如果值不在映射列表中,则标签将使用原始值进行处理。
注意: 这仅在使用已弃用的 netsnmp 转换器时才需要。当使用更新、更快的 gosmi 转换器时,可以使用以下配置来实现
[[inputs.snmp]]
## Agent addresses to retrieve values from.
agents = ["udp://127.0.0.1:161"]
[[inputs.snmp.field]]
oid = "SNMPv2-MIB::sysName.0"
name = "source"
is_tag = true
[[inputs.snmp.table]]
oid = "IF-MIB::ifTable"
name = "interface"
inherit_tags = ["source"]
[[inputs.snmp.table.field]]
oid = "IF-MIB::ifAdminStatus"
is_tag = true
conversion = "enum"
存储解析:
最后,让我们讨论如何使用 Starlark 处理器插件来派生 SNMP 字段的替代值。这方面的一个很好的例子是监控 hrStorageTable。在此表中,我们想重点介绍三个关键字段
- hrStorageAllocationUnits - 从此池分配的数据对象的大小,以字节为单位。
- hrStorageSize - 存储的大小由此条目表示,以 hrStorageAllocationUnits 为单位。
- hrStorageUsed - 已使用的存储总量。以 hrStorageAllocationUnits 为单位。
如您所见,hrStorageSize 和 hrStorageUsed 直接与存储在 hrStorageAllocationUnits 中的值相关。我们可以使用它来派生每个的总字节数
[[inputs.snmp]]
## Agent addresses to retrieve values from.
agents = ["udp://127.0.0.1:161"]
[[inputs.snmp.field]]
oid = "SNMPv2-MIB::sysUpTime.0"
name = "uptime"
conversion = "float(2)"
[[inputs.snmp.field]]
oid = "SNMPv2-MIB::sysName.0"
name = "source"
is_tag = true
[[inputs.snmp.table]]
oid = "HOST-RESOURCES-MIB::hrStorageTable"
name = "hrStorageTable"
inherit_tags = ["source"]
# Parse HOST-RESOURCES-MIB::hrStorageAllocationUnits
[[processors.starlark]]
alias = "hrStorageTable_processor"
namepass = ["hrStorageTable"]
## Source of the Starlark script.
source = '''
def apply(metric):
units = metric.fields.pop("hrStorageAllocationUnits", 0)
if units and "hrStorageSize" in metric.fields:
metric.fields["hrStorageSize"] *= units
if units and "hrStorageUsed" in metric.fields:
metric.fields["hrStorageUsed"] *= units
return metric
'''
完整的 Telegraf 配置可以在这里找到。
总结
因此,总而言之,以下是在使用 SNMP 插件时要记住的事项
- 在有意义的情况下,使用字段而不是表
- 每个插件一个 SNMP Agent
- 插件超时可能会因 Agent 速度慢而使您陷入困境
- 某些 SNMP 字段非常适合作为元数据标签,而不是指标字段
我们还讨论了一些很棒的处理器插件示例,您可以使用它们开始塑造您的 SNMP 数据。
通过参加免费的 InfluxDB 大学 Telegraf 数据采集课程,了解更多关于使用 Telegraf 采集数据的信息。