这是怎么回事
我每隔几分钟就通过包在 Python 2.7.8 中从几千个网络设备收集数据netsnmp
。我也在使用fastsnmpy
,以便我可以访问(更有效的) Net-SNMP 命令snmpbulkwalk
。
我正在尝试减少我的脚本使用的内存量。我正在运行同一脚本的三个实例,该脚本会在重新查询所有设备以获取我们想要的数据之前休眠两分钟。当我在其中创建原始脚本时,bash
它们在同时处于活动状态时会使用不到 500MB。然而,当我将其转换为 Python 时,每个实例占用 4GB ,这表明(对我而言)我的数据结构需要更有效地管理。即使在空闲时,它们总共消耗 4GB。
代码活动
我的脚本首先创建一个列表,我在其中打开一个文件并将目标设备的主机名附加为单独的值。这些通常包含 80 到 1200 个名称。
expand = []
f = open(self.deviceList, 'r')
for line in f:
line = line.strip()
expand.append(line)
从那里我设置 SNMP 会话并执行请求
expandsession = SnmpSession ( timeout = 1000000 ,
retries = 1, # I slightly modified the original fastsnmpy
verbose = debug, # to reduce verbose messages and limit
oidlist = var, # the number of attempts to reach devices
targets = expand,
community = 'expand'
)
expandresults = expandsession.multiwalk(mode = 'bulkwalk')
由于这两个 SNMP 包的行为方式,设备响应被解析为列表并存储到一个巨大的数据结构中。例如,
for output in expandresults:
print ouput.hostname, output.iid, output.val
#
host1 1 1
host1 2 2
host1 3 3
host2 1 4
host2 2 5
host2 3 6
# Object 'output' itself cannot be printed directly; the value returned from this is obscure
...
我必须遍历每个响应,组合相关数据,然后输出每个设备的完整响应。这有点困难例如,
host1,1,2,3
host2,4,5,6
host3,7,8,9,10,11,12
host4,13,14
host5,15,16,17,18
...
每个设备都有不同数量的响应。我不能循环期望每个设备都具有统一的任意数量的值来组合成一个字符串以写入 CSV。
我如何处理数据
我相信在这里我消耗了大量内存,但我无法解决如何简化流程同时删除访问过的数据。
expandarrays = dict()
for output in expandresults:
if output.val is not None:
if output.hostname in expandarrays:
expandarrays[output.hostname] += ',' + output.val
else:
expandarrays[output.hostname] = ',' + output.val
for key in expandarrays:
self.WriteOut(key,expandarrays[key])
目前我正在创建一个新字典,检查设备响应是否为空,然后将响应值附加到将用于写出 CSV 文件的字符串。
问题在于我实际上是在克隆现有的字典,这意味着我使用了两倍的系统内存。我想删除我在expandresults
移动它们时访问过的值,这样我就expandarrays
不会使用太多的 RAM。有没有一种有效的方法来做到这一点?还有更好的方法来降低我的代码的复杂性,以便更容易理解吗?
罪魁祸首
感谢那些回答的人。对于那些将来由于遇到类似问题而偶然发现此线程的人:fastsnmpy
软件包是大量使用系统内存的罪魁祸首。该multiwalk()
函数为每个主机创建一个线程,但一次完成,而不是设置某种上限。由于我的脚本的每个实例将处理多达 1200 个设备,这意味着 1200 个线程在短短几秒钟内被实例化并排队。使用该bulkwalk()
功能较慢,但仍然足够快以满足我的需求。两者之间的差异是 4GB 和 250MB(系统内存使用)。