Ceci est l'article sur le 11ème jour de NetOpsCoding AdventCalender.
Cette fois, je vais implémenter un graphique de trafic qui est presque toujours confirmé lors des opérations réseau, en utilisant une technologie appelée * WebSocket *. La démo et le code source sont collés à la fin.
** Cette méthode d'implémentation est implémentée en se référant à l'outil utilisé par @yuyarin pour le monitoring dans Cedec2015. ** **
Cacti, Zabbix, MRTG, etc. sont réputés comme outils de surveillance du trafic. Dans la plupart des cas, l'intervalle d'acquisition SNMP est d'environ 5 minutes. Fondamentalement, je suis satisfait de la confirmation, mais dans un travail réel tel que l'ouverture d'une nouvelle ligne / l'ajustement du trafic, je veux souvent voir le trafic à * à ce moment *. En fonction de l'appareil, le trafic en temps réel peut être surveillé sur une base CLI, mais est-il difficile de remarquer des changements dans l'état de plusieurs emplacements avec CLI, et y a-t-il un retard dans la détection d'anomalies?
Afin de résoudre un tel problème, je vais créer un graphique qui est * visuellement facile à comprendre et peut capturer les changements de trafic à court terme en temps réel.
WebSocket est une technologie relativement nouvelle. Vous pouvez décider librement du moment de l'envoi et de la réception des données et de la méthode de communication. Une fois que vous avez publié une session, vous pouvez facilement transférer des données dans les deux sens.
Le dessin graphique peut être réalisé avec l'un ou l'autre, mais de toute façon, je vais essayer d'utiliser WebSocket, qui semble être applicable à d'autres implémentations d'outils! !! Quoi qu'il en soit, utilisons-le immédiatement!
Pour afficher sur le Web, une plate-forme telle que nginx ou apache est requise. Ce serveur de démonstration utilise nginx. De plus, 8080 est utilisé pour la communication WS cette fois.
La bibliothèque WebSocket utilise tornado. Il y a Gevent-WebSocket, ws4py, etc., mais la tornade m'est venue le plus.
En outre, bien que HighCharts soit utilisé comme outil de dessin de graphique, il n'y a aucun problème avec d'autres outils de graphique qui peuvent être ajoutés dynamiquement. De plus, HightCharts est facturé sauf pour un usage personnel, donc ceux qui sont concernés devraient utiliser d'autres outils. ccchart est recommandé car il contient de nombreux échantillons.
Implémentons le côté serveur. L'implémentation côté serveur de WebSocket n'est pas difficile si seul le point de "traitement asynchrone" est supprimé. Lorsqu'il écoute un URI spécifique et que le client est connecté, il devient possible d'échanger librement des données entre eux, il devient donc possible d'envoyer le résultat de l'acquisition de SNMP. SNMP est acquis en exécutant des commandes par sous-processus, et les résultats sont extraits avec des expressions régulières. De plus, cette fois, l'OID qui regarde le compteur du NIC du propre serveur est spécifié.
Après avoir implémenté le code ci-dessous, exécutez-le simplement avec la commande python pour terminer la construction du serveur WebSocket!
ws_traffic_server.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import tornado.ioloop
import tornado.web
import tornado.websocket
from tornado.options import define, options ,parse_command_line
from datetime import datetime
import shlex, subprocess , time ,re , json ,threading
SLEEP_TIME = 20 #Intervalle pour obtenir SNMP
COMMUNITY = 'dev'
IP = '127.0.0.1'
IFMIB_OID = '1.3.6.1.2.1.31.1.1.1'
snmp_command_in = 'snmpget -v 2c -c %s %s %s.6.2'%(COMMUNITY,IP,IFMIB_OID)
snmp_command_out = 'snmpget -v 2c -c %s %s %s.10.2'%(COMMUNITY,IP,IFMIB_OID)
#Spécifiez le port que WebSocket écoute
define("port", default = 8080,type = int)
class SendWebSocket(tornado.websocket.WebSocketHandler):
#Événement appelé lorsqu'une connexion est sécurisée
def open(self):
print 'Session Opened. IP:' + self.request.remote_ip
#Événements lorsqu'un événement de déconnexion se produit, par exemple lorsque le navigateur est fermé
def on_close(self):
print "Session closed"
#Un événement appelé lorsqu'un message est envoyé par le client
def on_message(self, message):
if message == 'hello':
pre_counter_in = int(self.exe_snmp(snmp_command_in))
pre_counter_out = int(self.exe_snmp(snmp_command_out))
#Heure sur WebSocket.la minuterie ne peut pas être utilisée. Reproduisez le délai avec la variable suivante CallBack
#SLEE_Démarrer le traitement de la communication avec SNMP dans la seconde moitié après TIME secondes
tornado.ioloop.IOLoop.instance().call_later(SLEEP_TIME,self.snmp_second_half,{'in_counter':pre_counter_in,'out_counter':pre_counter_out})
#SLEEP_Obtenez SNMP après TIME secondes
def snmp_second_half(self,pre_counters):
result = {}
pos_counter_in = int(self.exe_snmp(snmp_command_in))
pos_counter_out = int(self.exe_snmp(snmp_command_out))
#Calcul du trafic à partir de la différence du compteur par rapport au nombre de secondes spécifié
traffic_in = (pos_counter_in - pre_counters['in_counter']) / SLEEP_TIME
traffic_out = (pos_counter_out - pre_counters['out_counter']) / SLEEP_TIME
#Envoyer des données de trafic converties en JSON à un client Web
try:
result.update({'traffic_in' : traffic_in , 'traffic_out' : traffic_out})
result.update({'timestamp' : time.mktime(datetime.now().timetuple())})
self.write_message(json.dumps(result))
except:
print "Client is already disconnectted."
#Renvoie uniquement la valeur du résultat de l'exécution SNMP
#e.g. [IF-MIB::ifHighSpeed.21 = Gauge32: 1000] -> [1000]
def exe_snmp(self,snmp_command):
split_command = shlex.split(snmp_command)
exec_output = subprocess.check_output(split_command)
r = re.compile("(.*)(: )(.*)")
snmp_result = r.match(exec_output).group(3)
return snmp_result
#Accepte uniquement les communications des hôtes spécifiés comme non Vrai
def check_origin(self, origin):
return True
#Attend une demande de connexion à WS à l'URI spécifié
app = tornado.web.Application([
(r"/ws/ifmon/", SendWebSocket),
])
if __name__ == "__main__":
parse_command_line()
app.listen(options.port)
mainloop = tornado.ioloop.IOLoop.instance()
mainloop.start() #Démarrez le serveur WebSocket
Ce qui est facile à acquérir ici, c'est le processus d'acquisition du trafic des périphériques réseau à partir de SNMP et de le calculer.
Calcul du trafic par SNMP
(IFcounter actuel --IFcounter après n secondes) / n
Puisqu'il ne peut pas être calculé sans attendre plusieurs dizaines de secondes, le programme doit également attendre n secondes.
Cependant, «time.sleep ()» dans la bibliothèque standard ne peut pas être utilisé pour une communication asynchrone telle que WebSocket. Étant donné que l'ensemble du processus est en veille, les autres téléspectateurs seront également affectés.
Cela a été résolu par une fonction dans tornado appelée ʻIOLoop.call_later () `qui peut rappeler après un délai.
Je pense que le programme est créé de force, donc j'apprécierais que vous puissiez commenter si vous devez l'écrire correctement.
Event | Moment de l'événement |
---|---|
onopen | Événement appelé lorsque la connexion avec le serveur est établie |
onmessage | Événements qui se produisent lorsque des données sont reçues(Place principale) |
onclose | Événement appelé lorsque la connexion avec le serveur est perdue |
onerror | Événement appelé lorsqu'une erreur se produit |
Lorsque la connexion au serveur est terminée et que l'événement «onopen» se produit, un signal «bonjour» est envoyé au serveur pour commencer à prendre SNMP. Lorsque vous envoyez «bonjour», le côté serveur réagit et envoie les données de trafic. Lorsque la réception de données du serveur est détectée, l'événement «message» est généré, de sorte que le graphique est dessiné dans cet événement. Si vous attrapez une action qui déconnecte le WebSocket, comme la fermeture du navigateur, l'événement ʻonclose` se produira et la communication s'arrêtera là.
Étant donné que les paramètres du graphique sont longs, je les omettrai. La partie pertinente du traitement WebSocket est implémentée comme suit.
ws_client.js
var WS_URL = 'ws://www5445uo.sakura.ne.jp:8080/ws/ifmon/'
var init_ws_Traffic = function(){
var traffic_chart =Traffic_Chart('traffic_chart', {}); //Constructeur de graphes Highhart
var ws = new WebSocket(WS_URL);
console.log('----- WebSocket Open -----')
ws.onopen = function() {//Établissement de la connexion WS
ws.send('hello');
};
ws.onerror = function(event){
$("p#error").text('Failed join to the server');
console.log('Connection faild....')
};
ws.onmessage = function(event) { //Traitement des données de trafic
var data = JSON.parse(event.data);
var timestamp = data['timestamp']*1000 + 60 * 9 * 60 * 1000;
var value = data['traffic_in']
document.getElementById('traffic_in').innerHTML = convert_bps(value); //Afficher sous forme de texte
traffic_chart.series[0].addPoint([timestamp, value], true, true); //L'ajout du graphique du trafic entrant se fait ici
value = data['traffic_out']
document.getElementById('traffic_out').innerHTML = convert_bps(value);
traffic_chart.series[1].addPoint([timestamp, value], true, true);//L'ajout du graphique du trafic sortant se fait ici
ws.send('hello'); //Prochaine demande de trafic
};
ws.onclose = function () {
ws.send('close');
ws.close();
};
window.onbeforeunload = function () {
ws.send('close');
ws.close()
};
}
Les deux ci-dessus sont nécessaires pour la communication WebSocket. Si vous vérifiez ce que vous avez réellement fait sur l'écran Web, cela ressemblera à ceci. C'est un graphique ...!
Vous pouvez désormais obtenir un graphique du trafic toutes les 10 secondes pour travailler! Si vous faites quelque chose de similaire et avez une meilleure méthode, faites-le moi savoir.
** Il n'y a pas de démo en direct car le serveur d'installation de démo a disparu **
En outre, le code utilisé dans la démo est répertorié ci-dessous. https://github.com/Mabuchin/wstraffic