Linux 提供了一些简单的工具,如 ps, top, free, df, vmstat 等,对于临时的查看系统资源和状态很有用,但对于一个大型的网络系统,我需要有长期自动获取的统计数据,来对服务器每天、每月、每年的资源和状态情况有一个整体上的认识,以及对 CPU/MEM/IO/Network trafic 的长期比较以确定性能瓶颈所在,并且能够长期监控关键服务,在出问题的时候自动发送邮件和短信等进行通知。
有一些可以在后台长期运行并周期查看系统资源的工具,如 sar,但它通常是针对一个单系统的,在多主机的环境下,其数据的管理就不太方便了;其抓取的二进制数据基本上只能自己使用,而这些数据并不具有直观性,不太利于分析,同时又缺乏其他工具的支持以使得数据能够以诸如图形的方式显示出来,所以对体系结构的建设来说并不是太好的选择。
相对来说,SNMP 数据的内容更加全面,而且其基于网络协议的方式使得管理多系统的大环境变得相对简单,其数据的组织形式也相对较好,它只提供系统当前状态的数据,而不像 sar 那样提高全部周期的数据,因此当前状态的数据可以做得非常详细,而统计的事情就交给其他工具去完成 -- 这符合 UNIX 的 KISS 原则:宁可要功能单一但非常专业的工具,然后将这些工具组合起来完成更复杂的任务。
通过其他工具的支持,可以取得长期的统计数据(如 Cacti),并将这些数据存储为更利于操作的形式,例如进行叠加、合并等(如 rrdtool)。
当然,其学习曲线不是那么平缓,
SNMP(Simple Network Management Protocal, 简单网络管理协议)在架构体系的监控子系统中将扮演重要角色。大体上,其基本原理是,在每一个被监控的主机或节点上 (如交换机)都运行了一个 agent,用来收集这个节点的所有相关的信息,同时监听 snmp 的 port,也就是 UDP 161,并从这个端口接收来自监控主机的指令(查询和设置)。
如果使用 RHEL4 的 net-snmp,那么被监控主机需要安装 net-snmp(包含了 snmpd 这个 agent),而监控端需要安装 net-snmp-utils。如果自行编译,需要 beecrypt(libbeecrypt)和 elf(libraryelf)的库。
每一个 agent 维护一个树形的数据库,称为 MID(Management Information Base, 管理信息库),其每一个节点称为 Object Identifier(OID),这在使用 net-snmp-utils 的工具时会用到。这些节点就表示了这台主机系统的设备如网卡的接口描述(eth0 等)、物理地址(MAC)、接口类型等,也可能是系统的信息,或者是需要监控的进程等...
net-snmp-utils 的工具集的所有参数不能直接在其 man 手册中查到,可以查 man snmpcmd ,这个命令并不实际存在,只是说明的所有 utils 命令共同的参数。
SNMP MIBs base && some utils
MID(Management Information Base, 管理信息库)这个树形数据库是按照数字(numeric)来组织的,即每一个节点(OID)都是数字,因此有一个名字到数字的映射关系,例如 system , interfaces 这样的名字要映射到各个被控端的实际设备节点上,或反之需要知道实际的名字。所有这些映射关系的定义都在 MIB 文件中,即 /usr/share/snmp/mibs (根据实际的安装情况会有不同)。例如:
sh$ grep 'system' /usr/share/snmp/mibs/SNMPv2-MIB.txt
system OBJECT IDENTIFIER ::= { mib-2 1 }
......
snmptranslate 这个命令可以用来查看映射关系:
sh$ snmptranslate .1.3.6.1.2.1.1.3.0
SNMPv2-MIB::sysUpTime.0
sh$ snmptranslate -On SNMPv2-MIB::system.sysUpTime.0
.1.3.6.1.2.1.1.3.0
可以看到这个 SNMPv2-MIB 其实就是 /usr/share/snmp/mibs/SNMPv2-MIB.txt。
如果要使用自定义的 local MIBs,可以参见: NET-SNMP Tutorial -- Using local MIBs
使用 snmpwalk 可以取得一个树的结果:
sh$ snmpwalk -v2c -c public localhost system
SNMPv2-MIB::sysDescr.0 = STRING: Linux localhost.localdomain 2.6.14.2 #1 SMP Thu Jan 11 15:39:36 EST 2007 i686
SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
SNMPv2-MIB::sysUpTime.0 = Timeticks: (687617) 1:54:36.17
SNMPv2-MIB::sysContact.0 = STRING:
SNMPv2-MIB::sysName.0 = STRING: localhost.localdomain
SNMPv2-MIB::sysLocation.0 = STRING: Unknown (edit /etc/snmp/snmpd.conf)
SNMPv2-MIB::sysORLastChange.0 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORID.1 = OID: IF-MIB::ifMIB
SNMPv2-MIB::sysORID.2 = OID: SNMPv2-MIB::snmpMIB
SNMPv2-MIB::sysORID.3 = OID: TCP-MIB::tcpMIB
SNMPv2-MIB::sysORID.4 = OID: IP-MIB::ip
SNMPv2-MIB::sysORID.5 = OID: UDP-MIB::udpMIB
SNMPv2-MIB::sysORID.6 = OID: SNMP-VIEW-BASED-ACM-MIB::vacmBasicGroup
SNMPv2-MIB::sysORID.7 = OID: SNMP-FRAMEWORK-MIB::snmpFrameworkMIBCompliance
SNMPv2-MIB::sysORID.8 = OID: SNMP-MPD-MIB::snmpMPDCompliance
SNMPv2-MIB::sysORID.9 = OID: SNMP-USER-BASED-SM-MIB::usmMIBCompliance
SNMPv2-MIB::sysORDescr.1 = STRING: The MIB module to describe generic objects for network interface sub-layers
SNMPv2-MIB::sysORDescr.2 = STRING: The MIB module for SNMPv2 entities
SNMPv2-MIB::sysORDescr.3 = STRING: The MIB module for managing TCP implementations
SNMPv2-MIB::sysORDescr.4 = STRING: The MIB module for managing IP and ICMP implementations
SNMPv2-MIB::sysORDescr.5 = STRING: The MIB module for managing UDP implementations
SNMPv2-MIB::sysORDescr.6 = STRING: View-based Access Control Model for SNMP.
SNMPv2-MIB::sysORDescr.7 = STRING: The SNMP Management Architecture MIB.
SNMPv2-MIB::sysORDescr.8 = STRING: The MIB for Message Processing and Dispatching.
SNMPv2-MIB::sysORDescr.9 = STRING: The management information definitions for the SNMP User-based Security Model.
SNMPv2-MIB::sysORUpTime.1 = Timeticks: (0) 0:00:00.00
SNMPv2-MIB::sysORUpTime.2 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.3 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.4 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.5 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.6 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.7 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.8 = Timeticks: (1) 0:00:00.01
SNMPv2-MIB::sysORUpTime.9 = Timeticks: (1) 0:00:00.01
sh$ snmpwalk -v2c -c public localhost interfaces
IF-MIB::interfaces = No Such Object available on this agent at this OID
如果增加 -Of 参数可以得到一个完整的树形表达。我不太明白这里的 system 和 interfaces 是如何定义和识别的?因为如果使用 snmpget 这样就不行:
sh$ snmpget -v2c -c public localhost system
SNMPv2-MIB::system = No Such Object available on this agent at this OID
sh$ snmpget -v2c -c public localhost SNMPv2-MIB::system
SNMPv2-MIB::system = No Such Object available on this agent at this OID
sh$ snmpget -v2c -c public localhost SNMPv2-MIB::sysDescr.0
SNMPv2-MIB::sysDescr.0 = STRING: Linux localhost.localdomain 2.6.14.2 #1 SMP Thu Jan 11 15:39:36 EST 2007 i686
现在我知道 interfaces 的一些 MIB(《Linux Server Hacks, 卷二》),前面用 snmpwalk 得不到结果,那么现在用 snmpget 呢?
sh$ snmpget -v2c -c public localhost IF-MIB::ifDescr.1
IF-MIB::ifDescr.1 = No Such Object available on this agent at this OID
再参考 net-snmp 的 FAQ,使用 snmpgetnext:
sh$ snmpgetnext -v2c -c public localhost IF-MIB::ifDescr.1
HOST-RESOURCES-MIB::hrSystemUptime.0 = Timeticks: (70364798) 8 days, 3:27:27.98
sh$ snmpgetnext -v2c -c public localhost HOST-RESOURCES-MIB::hrSystemUptime.0
HOST-RESOURCES-MIB::hrSystemUptime.0 = No more variables left in this MIB View (It is past the end of the MIB tree)
根据此 FAQ 上的说明,这样是会有问题的,因为实际上是使用了别的 MIB 文件,或者得到诸如"end of MIB"的响应,应该要更改配置,那么如何来做?在《Linux Server Hacks, Volume 2》上,是如下的表示:
IF-MIB::ifDescr.1 = STRING: lo
IF-MIB::ifDescr.2 = STRING: eth0
...
以上都是由于 SNMP 的 access control 配置引起的,SNMP 的 access control 可以控制对 MIB 树的某个分支可以由那些 IP 段来读取和修改等。
SNMP access control(未完)
前面已经了解了 SNMP 及其 MIBs,并且使用了一些工具来查看 MIB 树。但是问题是,我只能看到 system 这一分支的情况,即:
snmpwalk -v2c -c public localhost system
而 interfaces 就不行,这样如何监控网络的流量呢?而使用 snmpget 也得不到需要的 IF-MIB:: 中的信息,使用 snmpgetnext 得到的也不正确。snmpgetnext 应该是得到下一个(NEXT)节点的信息,例如:
sh$ snmpwalk -v2c -c demo 192.168.0.98 system | head -n 2
SNMPv2-MIB::sysDescr.0 = STRING: Linux localhost.localdomain 2.6.14.2 #1 SMP Thu Jan 11 15:39:36 EST 2007 i686
SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
sh$ snmpget -v2c -c demo 192.168.0.98 SNMPv2-MIB::sysDescr.0
SNMPv2-MIB::sysDescr.0 = STRING: Linux localhost.localdomain 2.6.14.2 #1 SMP Thu Jan 11 15:39:36 EST 2007 i686
sh$ snmpgetnext -v2c -c demo 192.168.0.98 SNMPv2-MIB::sysDescr.0
SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
这里 -c demo 是一个 community name,而且这里也不是使用的 localhost 而是 192.168.0.98 这样的地址,这是因为更改了 snmpd.conf 的缘故,实际上,如果不更改而使用默认的 snmpd.conf,那么只能使用 -c public localhost,否则只能得到诸如: "Timeout: No Response from 192.168.0.98."这样的信息。这些会在下面讲到。
根据 net-snmp FAQ "I can see the system group, but nothing else. Why?" 上的说明,无法得到 interfaces 这个子树的原因是由于 agent 的 access control 的缘故。那么在 netsnmp FAQ "How do I configure access control?" 和 net-snmp FAQ "I don't understand the new access control stuff - what does it mean?" 这两个部分说明了如何来配置 agent 的 access control。
我们现在只考虑 SNMPv2,不考虑 SNMPv3。 那么 access control 要解决的问题就是:我要让哪些人(who)可以获取哪些子树(what)。 与此相关的几个语句是 com2sec, group, view 和 access。
那么先来看看 access 语句,它就是定义哪些人可以获取哪些子树的语句。其语法为:
access {group} "" any noauth exact {read-tree} {write-tree} {notify-tree}
这里 {group} 就是将要用 group 语句来定义的组, {read-tree} {write-tree} {notify-tree} 就是将要用 view 来定义的子树。 所以 group 就是哪些人,view 就是哪些子树。
于是用 group 来定义哪些人:
# com2sec notConfigUser default public
# group notConfigGroup v1 notConfigUser
# group notConfigGroup v2c notConfigUser
com2sec mynet 192.168.0.0/24 demo
group gmynet v1 mynet
group gmynet v2c mynet
为了更清楚的说明,这里我将原来的注释掉了。v1/v2c 是 serurityModel,就是在 snmpwalk/snmpget 这些命令使用时使用的参数如 -v2c(-v 2c)。所以我们的 group 为 gmynet,它与 mynet 这个名字(security name)是一个映射关系,而为了简便起见,也可以直接定义 group 为 mynet,而不用绕这么多圈子:
group mynet v1 mynet
group mynet v2c mynet
com2sec 即 community to security,实际上定义了一个基于 地址的访问控制,另外它大概还有一个将 SNMPv2/SNMPv1 的名字映射过来的作用,如上的 demo,这样在 snmpwalk/snmpget 时使用 -v2c 这样的参数时可以使用 -c demo。按照上面的方式定义之后,就只能使用上面的 snmpwalk/snmpget -v2c -c demo 192.168.0.98 这样的形式,而不能再使用 -c public localhost 了,否则就得到 "Timeout: No Response from localhost"这样的出错。
然后用 view 来定义可以查看哪些子树:
view interface included .1.3.6.1.2.1.2
view system included .1.3.6.1.2.1.1
view system included .1.3.6.1.2.1.25.1.1
可以利用 snmptranslate 来得到 numeric 树,
sh$ snmptranslate -On IF-MIB::interfaces
.1.3.6.1.2.1.2
sh$ snmptranslate -On SNMPv2-MIB::system
.1.3.6.1.2.1.1
也可以直接使用 MIB 定义。
那么 access 的定义就应该如下:
access mynet "" any noauth exact system none none
access mynet "" any noauth exact interface none none
这样,按道理就应该可以得到 interfaces 的值了。记得要使 agent 重新读取配置文件,在 RHEL4 下面使用 /etc/init.d/snmpd restart 即可。
但实际上却不行:
sh$ snmpwalk -v2c -c demo 192.168.0.98 interfaces
IF-MIB::interfaces = No Such Object available on this agent at this OID
sh$ snmpget -v2c -c demo 192.168.0.98 IF-MIB::ifDescr.1
IF-MIB::ifDescr.1 = No Such Object available on this agent at this OID
但是如果使用如下的设置却可以:
view all included .1
access mynet "" any noauth exact all none none
sh$ snmpwalk -v2c -c demo 192.168.0.98 interface
IF-MIB::ifNumber.0 = INTEGER: 4
IF-MIB::ifIndex.1 = INTEGER: 1
IF-MIB::ifIndex.2 = INTEGER: 2
IF-MIB::ifIndex.3 = INTEGER: 3
IF-MIB::ifIndex.4 = INTEGER: 4
IF-MIB::ifDescr.1 = STRING: lo
IF-MIB::ifDescr.2 = STRING: eth0
IF-MIB::ifDescr.3 = STRING: eth1
IF-MIB::ifDescr.4 = STRING: sit0
IF-MIB::ifType.1 = INTEGER: softwareLoopback(24)
IF-MIB::ifType.2 = INTEGER: ethernetCsmacd(6)
IF-MIB::ifType.3 = INTEGER: ethernetCsmacd(6)
IF-MIB::ifType.4 = INTEGER: tunnel(131)
IF-MIB::ifMtu.1 = INTEGER: 16436
IF-MIB::ifMtu.2 = INTEGER: 1500
IF-MIB::ifMtu.3 = INTEGER: 1500
IF-MIB::ifMtu.4 = INTEGER: 1480
IF-MIB::ifSpeed.1 = Gauge32: 10000000
IF-MIB::ifSpeed.2 = Gauge32: 100000000
IF-MIB::ifSpeed.3 = Gauge32: 10000000
IF-MIB::ifSpeed.4 = Gauge32: 0
IF-MIB::ifPhysAddress.1 = STRING:
IF-MIB::ifPhysAddress.2 = STRING: 0:2:b3:b0:59:36
IF-MIB::ifPhysAddress.3 = STRING: 0:2:b3:b0:59:4a
IF-MIB::ifPhysAddress.4 = STRING: 0:0:0:0:59:4a
IF-MIB::ifAdminStatus.1 = INTEGER: up(1)
IF-MIB::ifAdminStatus.2 = INTEGER: up(1)
IF-MIB::ifAdminStatus.3 = INTEGER: down(2)
IF-MIB::ifAdminStatus.4 = INTEGER: down(2)
IF-MIB::ifOperStatus.1 = INTEGER: up(1)
IF-MIB::ifOperStatus.2 = INTEGER: up(1)
IF-MIB::ifOperStatus.3 = INTEGER: down(2)
IF-MIB::ifOperStatus.4 = INTEGER: down(2)
IF-MIB::ifInOctets.1 = Counter32: 381118
IF-MIB::ifInOctets.2 = Counter32: 125019173
IF-MIB::ifInOctets.3 = Counter32: 0
IF-MIB::ifInOctets.4 = Counter32: 0
IF-MIB::ifInUcastPkts.1 = Counter32: 4308
IF-MIB::ifInUcastPkts.2 = Counter32: 1069602
IF-MIB::ifInUcastPkts.3 = Counter32: 0
IF-MIB::ifInUcastPkts.4 = Counter32: 0
IF-MIB::ifInDiscards.1 = Counter32: 0
IF-MIB::ifInDiscards.2 = Counter32: 0
IF-MIB::ifInDiscards.3 = Counter32: 0
IF-MIB::ifInDiscards.4 = Counter32: 0
IF-MIB::ifInErrors.1 = Counter32: 0
IF-MIB::ifInErrors.2 = Counter32: 0
IF-MIB::ifInErrors.3 = Counter32: 0
IF-MIB::ifInErrors.4 = Counter32: 0
IF-MIB::ifOutOctets.1 = Counter32: 383414
IF-MIB::ifOutOctets.2 = Counter32: 1770179210
IF-MIB::ifOutOctets.3 = Counter32: 0
IF-MIB::ifOutOctets.4 = Counter32: 0
IF-MIB::ifOutUcastPkts.1 = Counter32: 4340
IF-MIB::ifOutUcastPkts.2 = Counter32: 1319881
IF-MIB::ifOutUcastPkts.3 = Counter32: 0
IF-MIB::ifOutUcastPkts.4 = Counter32: 0
IF-MIB::ifOutDiscards.1 = Counter32: 0
IF-MIB::ifOutDiscards.2 = Counter32: 0
IF-MIB::ifOutDiscards.3 = Counter32: 0
IF-MIB::ifOutDiscards.4 = Counter32: 0
IF-MIB::ifOutErrors.1 = Counter32: 0
IF-MIB::ifOutErrors.2 = Counter32: 0
IF-MIB::ifOutErrors.3 = Counter32: 0
IF-MIB::ifOutErrors.4 = Counter32: 0
IF-MIB::ifOutQLen.1 = Gauge32: 0
IF-MIB::ifOutQLen.2 = Gauge32: 0
IF-MIB::ifOutQLen.3 = Gauge32: 0
IF-MIB::ifOutQLen.4 = Gauge32: 0
IF-MIB::ifSpecific.1 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.2 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.3 = OID: SNMPv2-SMI::zeroDotZero
IF-MIB::ifSpecific.4 = OID: SNMPv2-SMI::zeroDotZero
sh$ snmpget -v2c -c demo 192.168.0.98 IF-MIB::ifDescr.1
IF-MIB::ifDescr.1 = STRING: lo
sh$ snmpget -v2c -c demo 192.168.0.98 IF-MIB::ifDescr.2
IF-MIB::ifDescr.2 = STRING: eth0
sh$ snmpgetnext -v2c -c demo 192.168.0.98 IF-MIB::ifDescr.2
IF-MIB::ifDescr.3 = STRING: eth1
那么最初的配置有什么问题呢?
无论如何,为安全起见,只做如下的 access:
sh$ snmptranslate .1.3.6.1.2.1
SNMPv2-SMI::mib-2
sh$ snmptranslate -Of .1.3.6.1.2.1
.iso.org.dod.internet.mgmt.mib-2
sh$ cat /etc/snmp/snmpd.conf
view system included .1.3.6.1.2.1
access mynet "" any noauth exact system none none
阅读(1599) | 评论(0) | 转发(0) |