Кой е най-ефективният начин за изстъргване на множество единични и разклонени OIDs?

Винаги съм във война между максимална скорост и минимална консумация на ресурси, така че целта ми е да намеря най-добрата комбинация за скорост и консумация на ресурси.
За всяко snmp устройство бих искал да сканирам oids под няколко клона.
Всеки клон има динамично количество oids под него, така че не знам какви конкретни oids ми трябват, просто знам, че имам нужда от всички oids под клон.
Имам някои устройства, които поддържат само SNMPv1, така че за тези устройства аз напишете код, който е съвместим с SNMPv1.
За останалите устройства използвам SNMPv2.

SNMPv1

Да кажем, че имам два OID, които бих искал да разходя по техните branch('1.3.6.1.2.1.4' and '1.3.6.1.2.1.6').
Под OID на клон имам предвид всички OID под даден клон.
Имам следния код:

cmdGen = cmdgen.AsynCommandGenerator()
cmdGen.asyncNextCmd(
  cmdgen.CommunityData('public', mpModel=1),
  cmdgen.UdpTransportTarget(('192.168.0.101', 161)),
  (str('1.3.6.1.2.1.4'),str('1.3.6.1.2.1.6'),),
  (__cbFun_Walk, (cmdgen.CommunityData('public', mpModel=1), cmdgen.UdpTransportTarget(('192.168.0.101', 161)))))
cmdGen.snmpEngine.transportDispatcher.runDispatcher()

Това работи добре, но единственият проблем е, че мога да спра само всички разходки наведнъж, следователно не мога да спра всяка разходка поотделно, така че всички разходки ще завършат, след като приключи най-дългата разходка.
Очевидно това е неефективно.
Мога също да напиша 2 asyncNextCmd за OID на клона:

cmdGen = cmdgen.AsynCommandGenerator()
cmdGen.asyncNextCmd(
        cmdgen.CommunityData('public', mpModel=1),
        cmdgen.UdpTransportTarget(('192.168.0.101', 161)),
        (str('1.3.6.1.2.1.4'),),
        (__cbFun_Walk, (cmdgen.CommunityData('public', mpModel=1),
        cmdgen.UdpTransportTarget(('192.168.0.101', 161))))) 
cmdGen.asyncNextCmd(
        cmdgen.CommunityData('public', mpModel=1),
        cmdgen.UdpTransportTarget(('192.168.0.101', 161)),
        (str('1.3.6.1.2.1.6'),),
        (__cbFun_Walk, (cmdgen.CommunityData('public', mpModel=1),
        cmdgen.UdpTransportTarget(('192.168.0.101', 161)))))
cmdGen.snmpEngine.transportDispatcher.runDispatcher()

Не познавам много добре SNMP, но предполагам, че вторият код има някои недостатъци.
Например на някои клиенти имам стотици SNMP устройства, така че отворих asyncCmd за всяко мрежово устройство едновременно.
Това доведе до много неотговарящи устройства и твърде високо използване на процесора.

SNMPv2

Също така бих искал да се опитам да разбера как работи груповото съдържание и дали мога да го използвам, за да направя кода си по-ефективен.
Да кажем, че имам 2 клона, които бих искал да премина.
1.3.6.1.2.1. 4.20, който има 5 oids, и 1.3.6.1.2.1.4.21, който има 39 oids.
Получавам всички стойности и в двата клона, но също така получавам повече стойности, отколкото искам.
Количеството стойности, които аз get винаги е клонът с най-голям брой oids, умножен по броя на клоновете, които имам.
Например клонът с най-много oids има 39 oids, а броят на клоновете е 2, така че 39*2=78, това означава, че getBulk ще върне 78 oids.
Искам getBulk да върне всички oids на клонове за всеки клон и не нищо повече, така че в моя случай искам 44 oids (39+5 = 44).
Това е моят код:

cmdGen = cmdgen.CommandGenerator()

errorIndication, errorStatus, errorIndex, varBindTable = cmdGen.bulkCmd(
  cmdgen.CommunityData('public'),
  cmdgen.UdpTransportTarget(('192.168.0.101', 161)),
  0, 1,
  '1.3.6.1.2.1.4.21', '1.3.6.1.2.1.4.20'
)

if errorIndication:
  print errorIndication
elif errorStatus:
  print '%s at %s\n' % (
    errorStatus.prettyPrint(),
    errorIndex and varBindTable[-1][int(errorIndex)-1] or '?'
  )
else:
  for varBindTableRow in varBindTable:
    for name, val in varBindTableRow:
      print str(name.prettyPrint()) + ' = ' + str(val.prettyPrint())

И така, кой е най-ефективният начин за изтриване на OID на множество разклонения както за SNMPv1, така и за SNMPv2?


person yuval    schedule 20.10.2015    source източник


Отговори (2)


Първото нещо, което трябва да разберете е, че не можете да инструктирате SNMP агента да ви върне точно „клон“. Такава операция не се поддържа в SNMP (на ниво протокол). Мениджърът има контрол по отношение на това какви OID да поиска и кога да спре. Агентът може да върне точния един OID (GET) или следващия OID (GETNEXT/GETBULK) или приблизителния брой следващи OID наведнъж (GETBULK).

В случай, че имате динамични OID, не можете надеждно да предвидите колко от тях има в даден момент. Следователно не мисля, че бихте могли да получите стриктно OID на клоновете не повече или по-малко в една SNMP операция.

Като казах това, мисля, че трябва да се опитате да използвате GETBULK, когато е възможно. Насочете се към максималния очакван брой OID, за да ги вземете в една операция GETBULK. Но проверете в кода си дали наистина получавате всичко (агентът може да не върне заявения брой OID наведнъж).

Що се отнася до pysnmp API, който използвате, за да спрете неговата итерация GETBULK/GETNEXT, трябва да върнете True от вашата функция за обратно извикване. Можете да анализирате какви OID получавате от агента там и да върнете True, когато те надхвърлят клона, който ви интересува. Това ще прекрати извличането на един клон, останалите ще продължат да работят.

Дизайнът, при който изпращате множество паралелни заявки към един и същ SNMP агент за различни OID, очевидно е много по-малко ефективен.

person Ilya Etingof    schedule 20.10.2015
comment
Можете ли да обясните или покажете какво имате предвид под Можете да добавяте и премахвате OID от PDU заявка в движение. Например, когато един OID е изчерпан, вие просто го изваждате от PDU на заявката и продължавате с останалите OID. - person yuval; 21.10.2015

Искате bulkCmd, както е описано в

http://pysnmp.sourceforge.net/examples/current/v3arch/oneliner/manager/cmdgen/getbulk-v2c.html

Той ще върне данните от мрежовото устройство на по-малко и по-големи парчета.

person k1eran    schedule 20.10.2015