この記事では、SNMP情報の取得とパフォーマンステストを同時に行うpythonの詳細な説明を主に紹介していますが、編集者が非常に優れていると感じたので、参考として共有します。エディターをフォローして見てみましょう
python & snmp
Python を使用して SNMP 情報を取得するために利用できる既製のライブラリが多数ありますが、その中で最もよく使用される 2 つのライブラリは netsnmp
和pysnmp
です。インターネット上には 2 つのライブラリの例が多数あります。
この記事の焦点は、SNMP データを同時に取得する方法、つまり、複数のマシンから同時に SNMP 情報を取得する方法です。
netsnmp
まず netsnmp について話しましょう。 Python の netsnmp は、実際には net-snmp パッケージから来ています。
Python は net-snmp インターフェイスを呼び出し、c ファイルを通じてデータを取得します。
そのため、複数のマシンを同時に取得する場合、コルーチンを使用して取得することはできません。コルーチンを使用するため、データを取得する際、ソケットを使用する場合のようにデータを待機中に CPU を他のコルーチンに切り替えるのではなく、コルーチンは常に net-snmp インターフェイスからデータが返されるのを待ちます。この観点からすると、コルーチンの使用とシリアルフェッチに違いはありません。
では、同時取得の問題を解決するにはどうすればよいでしょうか?スレッドやマルチスレッド取得も利用できます(もちろんマルチプロセスも利用可能)。複数のスレッドが net-snmp インターフェイスを呼び出して同時にデータを取得し、CPU が複数のスレッドを継続的に切り替えます。スレッドは結果を取得した後、引き続きインターフェイスを呼び出して次の SNMP データを取得できます。
ここでサンプルプログラムを書きました。まず、すべてのホストと oid をタスクにしてキューに入れ、複数のスレッドを起動して取得タスクを実行します。プログラムのサンプルは次のとおりです。
import threading import time import netsnmp import Queue start_time = time.time() hosts = ["192.20.150.109", "192.20.150.110", "192.20.150.111", "192.20.150.112", "192.20.150.113", "192.20.150.114", "192.20.150.115", "192.20.150.116", "192.20.150.117", "192.20.150.118", "192.20.150.119", "192.20.150.120", "192.20.150.121", "192.20.80.148", "192.20.80.149", "192.20.96.59", "192.20.82.14", "192.20.82.15", "192.20.82.17", "192.20.82.19", "192.20.82.12", "192.20.80.139", "192.20.80.137", "192.20.80.136", "192.20.80.134", "192.20.80.133", "192.20.80.131", "192.20.80.130", "192.20.81.141", "192.20.81.140", "192.20.82.26", "192.20.82.28", "192.20.82.23", "192.20.82.21", "192.20.80.128", "192.20.80.127", "192.20.80.122", "192.20.81.159", "192.20.80.121", "192.20.80.124", "192.20.81.151", "192.20.80.118", "192.20.80.119", "192.20.80.113", "192.20.80.112", "192.20.80.116", "192.20.80.115", "192.20.78.62", "192.20.81.124", "192.20.81.125", "192.20.81.122", "192.20.81.121", "192.20.82.33", "192.20.82.31", "192.20.82.32", "192.20.82.30", "192.20.81.128", "192.20.82.39", "192.20.82.37", "192.20.82.35", "192.20.81.130", "192.20.80.200", "192.20.81.136", "192.20.81.137", "192.20.81.131", "192.20.81.133", "192.20.81.134", "192.20.82.43", "192.20.82.45", "192.20.82.41", "192.20.79.152", "192.20.79.155", "192.20.79.154", "192.25.76.235", "192.25.76.234", "192.25.76.233", "192.25.76.232", "192.25.76.231", "192.25.76.228", "192.25.20.96", "192.25.20.95", "192.25.20.94", "192.25.20.93", "192.24.163.14", "192.24.163.21", "192.24.163.29", "192.24.163.6", "192.18.136.22", "192.18.136.23", "192.24.193.2", "192.24.193.19", "192.24.193.18", "192.24.193.11", "192.20.157.132", "192.20.157.133", "192.24.212.232", "192.24.212.231", "192.24.212.230"] oids = [".1.3.6.1.4.1.2021.11.9.0",".1.3.6.1.4.1.2021.11.10.0",".1.3.6.1.4.1.2021.11.11.0",".1.3.6.1.4.1.2021.10.1.3.1", ".1.3.6.1.4.1.2021.10.1.3.2",".1.3.6.1.4.1.2021.10.1.3.3",".1.3.6.1.4.1.2021.4.6.0",".1.3.6.1.4.1.2021.4.14.0", ".1.3.6.1.4.1.2021.4.15.0"] myq = Queue.Queue() rq = Queue.Queue() #把host和oid组成任务 for host in hosts: for oid in oids: myq.put((host,oid)) def poll_one_host(): while True: try: #死循环从队列中获取任务,直到队列任务为空 host, oid = myq.get(block=False) session = netsnmp.Session(Version=2, DestHost=host, Community="cluster",Timeout=3000000,Retries=0) var_list = netsnmp.VarList() var_list.append(netsnmp.Varbind(oid)) ret = session.get(var_list) rq.put((host, oid, ret, (time.time() - start_time))) except Queue.Empty: break thread_arr = [] #开启多线程 num_thread = 50 for i in range(num_thread): t = threading.Thread(target=poll_one_host, kwargs={}) t.setDaemon(True) t.start() thread_arr.append(t) #等待任务执行完毕 for i in range(num_thread): thread_arr[i].join() while True: try: info = rq.get(block=False) print info except Queue.Empty: print time.time() - start_time break
netsnmp get 操作のサポートに加えて、walk 操作、つまり oid の走査もサポートします。
ただし、walk を使用する場合は、高遅延などの問題を避けるために注意する必要があります。詳細については、snmpwalk 高遅延の問題分析に関する以前のブログを参照してください。
pysnmp
pysnmp は、Python で実装された SNMP プロトコル ライブラリのセットです。それ自体が非同期のサポートを提供します。
import time import Queue from pysnmp.hlapi.asyncore import * t = time.time() myq = Queue.Queue() #回调函数。在有数据返回时触发 def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): myq.put((time.time()-t, varBinds)) hosts = ["192.20.150.109", "192.20.150.110", "192.20.150.111", "192.20.150.112", "192.20.150.113", "192.20.150.114", "192.20.150.115", "192.20.150.116", "192.20.150.117", "192.20.150.118", "192.20.150.119", "192.20.150.120", "192.20.150.121", "192.20.80.148", "192.20.80.149", "192.20.96.59", "192.20.82.14", "192.20.82.15", "192.20.82.17", "192.20.82.19", "192.20.82.12", "192.20.80.139", "192.20.80.137", "192.20.80.136", "192.20.80.134", "192.20.80.133", "192.20.80.131", "192.20.80.130", "192.20.81.141", "192.20.81.140", "192.20.82.26", "192.20.82.28", "192.20.82.23", "192.20.82.21", "192.20.80.128", "192.20.80.127", "192.20.80.122", "192.20.81.159", "192.20.80.121", "192.20.80.124", "192.20.81.151", "192.20.80.118", "192.20.80.119", "192.20.80.113", "192.20.80.112", "192.20.80.116", "192.20.80.115", "192.20.78.62", "192.20.81.124", "192.20.81.125", "192.20.81.122", "192.20.81.121", "192.20.82.33", "192.20.82.31", "192.20.82.32", "192.20.82.30", "192.20.81.128", "192.20.82.39", "192.20.82.37", "192.20.82.35", "192.20.81.130", "192.20.80.200", "192.20.81.136", "192.20.81.137", "192.20.81.131", "192.20.81.133", "192.20.81.134", "192.20.82.43", "192.20.82.45", "192.20.82.41", "192.20.79.152", "192.20.79.155", "192.20.79.154", "192.25.76.235", "192.25.76.234", "192.25.76.233", "192.25.76.232", "192.25.76.231", "192.25.76.228", "192.25.20.96", "192.25.20.95", "192.25.20.94", "192.25.20.93", "192.24.163.14", "192.24.163.21", "192.24.163.29", "192.24.163.6", "192.18.136.22", "192.18.136.23", "192.24.193.2", "192.24.193.19", "192.24.193.18", "192.24.193.11", "192.20.157.132", "192.20.157.133", "192.24.212.232", "192.24.212.231", "192.24.212.230"] oids = [".1.3.6.1.4.1.2021.11.9.0",".1.3.6.1.4.1.2021.11.10.0",".1.3.6.1.4.1.2021.11.11.0",".1.3.6.1.4.1.2021.10.1.3.1", ".1.3.6.1.4.1.2021.10.1.3.2",".1.3.6.1.4.1.2021.10.1.3.3",".1.3.6.1.4.1.2021.4.6.0",".1.3.6.1.4.1.2021.4.14.0", ".1.3.6.1.4.1.2021.4.15.0"] snmpEngine = SnmpEngine() #添加任务 for oid in oids: for h in hosts: getCmd(snmpEngine, CommunityData('cluster'), UdpTransportTarget((h, 161), timeout=3, retries=0,), ContextData(), ObjectType(ObjectIdentity(oid)), cbFun=cbFun) time1 = time.time() - t #执行异步获取snmp snmpEngine.transportDispatcher.runDispatcher() #打印结果 while True: try: info = myq.get(block=False) print info except Queue.Empty: print time1 print time.time() - t break
pysnmp 自体は最も基本的な get および getnext コマンドのみをサポートしているため、walk を使用したい場合は自分で実装する必要があります。
パフォーマンステスト
同じ環境で、両方のパフォーマンステストを実施しました。 2人は198匹のホストと10匹のオイドを集めた。
テストグループ | 所要時間(秒) |
---|---|
netsnmp(20スレッド) | 6.252 |
netsnmp(50スレッド) | 3.269 |
netsnmp(200スレッド) | 3.265 |
pysnmp | 4.812 |
netsnmpの収集速度はスレッド数に関係していることがわかります。スレッド数がある程度増加すると、収集時間が短縮されなくなります。スレッドを開くのも時間がかかるからです。既存のスレッドで十分に処理できます。
pysnmp のパフォーマンスが若干悪くなります。 pysnmpの詳細解析にはタスク追加時(getCmd実行時)に約1.2秒、その後の収集には約3.3秒かかります。
oidの数を増やして実験を行っています。ホストはまだ 198 個、oid は 42 個あります。
テストグループ | 所要時間(秒) |
---|---|
netsnmp(20スレッド) | 30.935 |
netsnmp(50スレッド) | 12.91 4 |
netsnmp(200スレッド) | 4.044 |
pysnmp | 11.043 |
さらに差が開いていることがわかります。十分なスレッドがある場合、netsnmp は pysnmp よりも大幅に効率的です。
どちらも複数のホストの並行収集をサポートしているため、使いやすさの点では netsnmp の方がシンプルであり、netsnmp はウォーク機能をサポートしています。この記事では netsnmp を推奨します。
インストールnetsnmp には net-snmp がインストールされている必要があります。 centosの場合はyumを使うと便利です。
以上がPythonによるSNMP情報の同時取得と性能テスト方法を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。