问题出现
有两台物理机,一台是192.168.1.15
,另一台是192.168.1.43
。二者的netsnmp版本相同。
使用snmpwalk去访问两台机器,获取tcp重传数(tcpRetransSegs)时,192.168.1.43
回复时间非常长。多达140s+,但是相同配置的192.168.1.15
只需要30ms。
-bash-4.1# time snmpwalk -v 2C -c cluster -t 200 -r 0 192.168.1.15 .1.3.6.1.2.1.6.12
TCP-MIB::tcpRetransSegs.0 = Counter32: 2364728
real 0m0.030s
user 0m0.020s
sys 0m0.003s
-bash-4.1# time snmpwalk -v 2C -c cluster -t 200 -r 0 192.168.1.43 .1.3.6.1.2.1.6.12
TCP-MIB::tcpRetransSegs.0 = Counter32: 3771986491
real 2m27.554s
user 0m0.020s
sys 0m0.003s
这个现象非常奇怪,按理说tcpRetransSegs
是从/proc/net/snmp
中直接拿数据然后解析,耗时应该非常短。不应该到秒级。
而且在使用time snmpwalk -v 2C -c cluster -t 200 -r 0 192.168.1.43 .1.3.6.1.2.1.6.12
进行访问时,是立即返回了TCP-MIB::tcpRetransSegs.0 = Counter32: 3771986491
的信息,但是接着卡住长达140s+,然后该命令才结束。
说明返回tcpRetransSegs
的数据并没有消耗多少时间,但是之后未知的流程导致了巨大时间的消耗。
问题分析
对比了两台机器,发现二者最大的区别在于192.168.1.15
上有较少的连接数,大概10+。而192.168.1.43
上有多达4000+的连接数。
尝试只用snmpget
来获取192.168.1.43
上tcpRetransSegs
的值
-bash-4.1# time snmpget -v 2C -c cluster -t 200 -r 0 192.168.1.43 .1.3.6.1.2.1.6.12.0
TCP-MIB::tcpRetransSegs.0 = Counter32: 3850778646
real 0m0.025s
user 0m0.023s
sys 0m0.002s
可以发现立即返回,而使用snmpwalk
依然耗时巨大。
snmpwalk
snmpwalk
是遍历mib上的某棵子树,包含了至少两个动作,get和getnext。
首先对于oid进行get操作,然后进行getnext,获取返回值和名称(oid)。
然后判断该返回的oid是否还在这个子树上,如果不在了,那么就结束。
如果还在该子树上,则使用返回的oid继续getnext,直到结束。
具体来说,就是time snmpwalk -v 2C -c cluster -t 200 -r 0 192.168.1.43 .1.3.6.1.2.1.6.12
命令可以分为以下几部分:
首先对oid.1.3.6.1.2.1.6.12
进行get。
-bash-4.1# time snmpget -v 2C -c cluster -t 200 -r 0 192.168.1.43 .1.3.6.1.2.1.6.12
TCP-MIB::tcpRetransSegs = No Such Instance currently exists at this OID
real 0m0.025s
user 0m0.019s
sys 0m0.001s
然后进行getnext
-bash-4.1# time snmpgetnext -v 2C -c cluster -t 200 -r 0 192.168.1.43 .1.3.6.1.2.1.6.12
TCP-MIB::tcpRetransSegs.0 = Counter32: 3815361069
real 0m0.025s
user 0m0.022s
sys 0m0.001s
因为返回的tcpRetransSegs.0
在.1.3.6.1.2.1.6.12
树上,因此继续getnext
-bash-4.1# time snmpgetnext -v 2C -c cluster -t 200 -r 0 192.168.1.43 .1.3.6.1.2.1.6.12.0
TCP-MIB::tcpConnState.0.0.0.0.22.0.0.0.0.0 = INTEGER: listen(2)
real 2m20.125s
user 0m0.022s
sys 0m0.002s
这次返回的tcpConnState.0.0.0.0.22.0.0.0.0.0
已经出了.1.3.6.1.2.1.6.12
树,因此snmpwalk
结束。
这里也可以看到主要的耗时就是在这一步上了。而这一步耗时的主要原因是获取tcpConnState
需要将所有的连接遍历一遍。
这也与观察到的192.168.1.43
上连接数高相吻合。
结论
time snmpwalk -v 2C -c cluster -t 200 -r 0 192.168.1.43 .1.3.6.1.2.1.6.12
耗时巨大的主要原因是错用了snmpwalk
。导致去获取tcpConnState
的数据,从而致使snmpd
在分析所有的连接时,耗费了巨大的时间和CPU资源。
正确的方法应该是使用snmpget -v 2C -c cluster -t 200 -r 0 192.168.1.43 .1.3.6.1.2.1.6.12.0
去获取数据。
这里也有一个教训,就是如果能够准确回去的oid数据,最好使用get,使用getnext会降低其效率。