問題出現
有兩台物理機,一台是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會降低其效率。
