使用SNMP进行监视

首先

使用SNMP进行监控是从很久以前就开始了的,
MRTG、Munin、Cacti、Zabbix等等,有很多工具可以选择。
但最近流行的开源软件监控工具很受欢迎,我想尝试一下,看看能否轻松地实现监控。

我对collectd、fluentd和prometheus进行了比较。

由于Collectd和Fluentd用于数据路由,所以假定使用Graphite、InfluxDB等作为数据存储。但是由于这些配置目前并不相关,所以没有在此处提及。

收集数据

插件可以做到。
设置可以进行调整。

LoadPlugin snmp
<Plugin snmp>
  <Data "dataname">
    Type "tipename"
    Table true
    Instance "IF-MIB::ifDescr"
    Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
  </Data>
  <Data "dataname">
    Type "users" 
    Table false
    Instance ""
    Shift -1
    Values "HOST-RESOURCES-MIB::hrSystemNumUsers.0"
  </Data>
  <Host "Hostname">
    Address "192.168.1.1"
    Version 2
    Interval 60
    Community "another_string"
    Collect "dataname" "dataname" "dataname"
  </Host>
</Plugin>

插件加载,
数据定义,如果是索引的话,要使用在 Instance 中指定的内容作为索引名称。
主机定义(指定要收集的数据)。
由于数据定义和主机定义是分开的,所以设置不会变得很复杂。
但是,无法对数据定义进行分组,所以主机的收集可能会变得非常冗长。

Fluentd 流畅日志管理工具

在插件中可以进行适配。
设置可以调整。

<source>
  type snmp
  tag snmp.hostname
  host "192.168.1.1"
  Community "another_string"
  mib ifDescr, ifInOctets, ifOutOctets
  method_type walk
  polling_time 1
  out_executor "/path/of/exec.rb"
</source>
<source>
  type snmp
  tag snmp.hostname
  host "192.168.1.1"
  Community "another_string"
  mib "hrSystemNumUsers.0"
  method_type get
</source>

由于要对主机名和数据进行定义设置,所以当要收集的数据和主机数量增多时,源定义会不断增加,这很麻烦。如果什么都不做,收集到的数据会以Value={Name=hoge,Value=fuga}这样的形式传送,所以可能需要准备exec.rb进行处理,否则会很麻烦。

以下是我尝试将接口加工成 ifDescr.ifInOctets=value,ifDescr.ifOutOctets=value 的输出结果。

module Fluent
  class SnmpInput
    def out_exec manager, opts={}
      manager.walk(opts[:mib]) do |row|
        time = Time.now.to_i
        time = time - time  % 5
        record = {}
        data = {}
        row.each do |vb|
          data["name"] = vb.value.to_s if vb.name.to_s =~ /Descr/
          data["InOctets"] = vb.value.to_s if vb.name.to_s =~ /InOctets/
          data["OutOctets"] = vb.value.to_s if vb.name.to_s =~ /OutOctets/
        end
        if data.has_key?("name")
          record["#{data['name']}.InOctets"] = data["InOctets"] if data.has_key?("InOctets")
          record["#{data['name']}.OutOctets"] = data["OutOctets"] if data.has_key?("OutOctets")
        end
        if record
          router.emit opts[:tag], time, record
        end
      end
    end
  end
end

由于我们只关注值,不用担心收集数据类型是否是计数器,所以如果能进行差分计算,那么需要使用另外的fluentd筛选器或者数据存储进行处理,然后将其作为计数器值输入。

普罗米修斯

可以使用Exporter进行处理。
配置分别由snmp_exporter和Prometheus进行。
数据定义由snmp_exporter处理,轮询设置由Prometheus处理。

specialnode:
   version: 2
   auth:
      community: "another_string"
   walk:
      - 1.3.6.1.2.1.2
      - 1.3.6.1.2.1.25.1.5
   metrics:
      - name: ifInOctets
        oid: 1.3.6.1.2.1.2.2.1.10 
        indexes:
          - labelname: ifDescr
            type: Integer32
        lookups:
          - labelname: ifDescr
            oid: 1.3.6.1.2.1.2.2.1.2
      - name: ifOutOctets
        oid: 1.3.6.1.2.1.2.2.1.16 
        indexes:
          - labelname: ifDescr
            type: Integer32
        lookups:
          - labelname: ifDescr
            oid: 1.3.6.1.2.1.2.2.1.2
      - name: hrSystemNumUsers
        oid: 1.3.6.1.2.1.25.1.5 

以下是snmp_exporter的数据定义。
在这里,我们使用名为specialnode的名称进行了一个定义。

在这个状态下,运行snmp_exporter,
使用curl命令”curl “http://snmp_exporterhost:9116/snmp?targer=hostname&module=specialnode”
可以看到可以捕获到数据。

scrape_configs:
  - job_name: 'snmp'
    scrape_interval: 60s
    target_groups:
      - targets:
        - 192.168.1.1
    metrics_path: /snmp
    params:
      module: [specialnode]
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 127.0.0.1:9116

在 Prometheus 的一侧,我们将其注册为作业,并定期从 Prometheus 前往 snmp_exporter 进行数据收集。
与 fluentd 类似,Prometheus 对于计数器数据无法直接进行差分计算等操作,因此需要进行处理。
但是,由于我还没有进行过相关研究,所以不清楚这方面是否会很麻烦。

在Prometheus中进行差分计算

在Prometheus中,提供了一个名为rate的聚合函数作为差分计算方法。
根据上述配置,收集到的数据包括每60秒的ifInOctets等内容,
如果在Graph的表达式中写入rate(IfInOctets[5m]),则会显示5分钟内的差分。
此外,还可以在配置文件中添加该设置。

rule_files:
  - prometheus.rule

在文件(prometheus.rule)中记录并描述收集规则。

ifInOctets_5min_rate = rate(ifInOctets[5m])

如果要记录,将以 ifInOctets_5min_rate 为名称保存5分钟的差分值。
由于计算率需要两个数据,所以如果要计算1分钟的差分值,需要进行一些调整,例如将 scrape_interval 设为30秒。

ifInbps_5min_average = rate(ifInOctets[5m])*8/300

我们也可以这样计算bps。

结尾

我已经确认了使用SNMP进行监视所需的设置差异。就设置文件的编写而言,仅使用fluentd好像不太适合这个用途,感觉有些麻烦。不管怎样,如果有人说我们会创建这样的生成器,那就无话可说了。

广告
将在 10 秒后关闭
bannerAds