我尽量长话短说,大家能理解中心思想即可。
事件背景
公司有国际业务,现有数据中心在UCLOUD 香港,国内和香港的网络掉包严重。所以考虑换数据中心,于是要测现有国内外服务器和供选择的新数据中心的网络情况。主要测试网络时延和丢包情况。这可能有现有工具(如果你们知道请评论留言)1是我懒得去弄zabbix,zabbix应该是可以通过UserParams来收集各个节点到指定IP的网络情况。2主要是我想练一下django,试一下highchart怎么用。因为我本身web前端都不在行,平常都弄运维了。所以就有自己写这件事情。
技术思路
各个节点的服务器运行一个agent.py进行网络情况的收集,并把数据通过web api POST到web服务器上。Web服务器使用django,提供一个收集数据的api,另外提供一个简单的查询页面,把取出的数据用highchart画图。 这个逻辑很简单。最终画出的图是这样的:
开发前的环境部署:
Server: ubuntu,django 1.8 ,python 2.7
技术关键点
我们从agent到web数据收集,到图形展示的顺序来讲:
1、agent数据收集,上传。2、服务器接口设计 3、服务器页面展示 4、nginx+uwsgi部署
1、 agent收集&上传数据
数据收集策略:通过ping –n –c 60 ip 然后获取最终的数据,min/max/avg loss , ping 60个包约1分钟。即客户端1分钟取一个数据点,并上传给服务端。
以下是agent.py的内容(很粗略,Python刚入门)
import re,urllib2,urllib,datetime import subprocess,json,time,sys sourceip = "localip" dest = sys.argv[1] postapi = http://serverip/getping #获取ping的数据并把数据post到指定的服务器api里面,主要通过urllib2来实现。 def Curlpost(web,data): values =urllib.urlencode(data) req =urllib2.Request(web,values) response =urllib2.urlopen(req) result =response.read() #通过ping来获取具体的网络监测情况。Subprocess的作用是新建一个进程来执行我们提供的命令。然后把进行的输出重定向到PIPE,具体的建议大家自己到网络上去搜。然后从获取的输出out中读取我们需要的东西。这个步骤通过re(正则)模块来完成,具体的功能同样建议到网络搜索。主要功能是通过正则表达式来匹配出我们需要的内容如匹配数字123.123 \d+\.\d+ ,我比较少使用正则一些复杂的不会使用。(如果有人有去测试的话,有比较好的匹配方法,请留言) def getpingdata(): try: ping = subprocess.Popen(["ping", "-n", "-c60", dest], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, error = ping.communicate() if out: data={} #通过re,正则来匹配出我们想要的内容。以后的data[]=m[x] 就是取出具体的哪些数据。 m=re.findall(r"\d+\.\d+",out) a=re.findall(r"\d+\%",out) data[‘min‘]=m[-4] data[‘avg‘]=m[-3] data[‘max‘]=m[-2] data[‘loss‘]=a[0].split(‘%‘)[0] #此处获取当时的时间搓,并通过time生成当天的日期和时间,这三个数据都会存放在服务器上。 t=time.time() data[‘time‘]=t data[‘day‘]=time.strftime("%Y-%m-%d",time.localtime(t)) data[‘hour‘]=time.strftime("%H:%M:%S",time.localtime(t)) #存储源IP和目标IP data[‘destip‘]=dest data[‘sourceip‘]=sourceip #所有需要的数据都装到data{}里面了。 returndata else: print ‘Noping‘ except: print "no data" #无限循环来进行获取,提交数据。 while 1: data = getpingdata() Curlpost(postapi,data) |
2、 服务器接口设计
服务器端通过django实现,数据存在MySQL中。
2.1环境准备
#apt-get install python-dev python-MysqlDB django
#wget https://www.djangoproject.com/download/1.8.7/tarball/
# tar –zxvf Django-1.8.7.tar.gz
#cd django-1.8.7
#pythonsetup.py install
#可能需要安装setuptools
#Python
> import django #测试django已经安装完成
#说明这里django我是跟着官文一步一步跟着学习,实践它本身的例子。所以这里的app和官文一样用polls,我也懒得换。
#创建djnago项目
#cd /data
#django-admin startproject dos #会帮我们自动穿件一个dos目录。
#创建app
#django-adminstartapp polls
接下来要做的步骤是,设置数据库连接参数,同步数据库,测试django是否可以运行,在setting配置静态模模板template路劲,激活polls app 。
#设置数据库连接 编辑setting.py
#在INSTALLED_APPS 添加polls
静态模板设置:
数据库设置:
#进行数据库同步
#cd /data/dos/
#python manage.py makemigrations
#python manage.py migrate
#以上两部完成后django会自动帮我们创建出相应的一些初始化的表,可以在库中看到。
以上基本的环境准备完毕,开始设计我们的数据存储的表(model)和我们具体的接口(view)
#如果大家对django不熟悉,就阅读下文档。https://docs.djangoproject.com/en/1.8/ 这个有几个part,总的6的看完就可以写。
2.2 服务端接受数据的接口设计:
数据表model.py
#这些字段都很好理解,IP,ping的数据,agent数据的采集时间点。(分为日期,时间,时间戳)具体出现的datatime,time大家自行实践都能明白。
class PingData(models.Model): sourceip = models.IPAddressField(null=True) destip = models.IPAddressField(null=True) min = models.FloatField(default=1) max = models.FloatField(default=1) avg = models.FloatField(default=1) loss = models.IntegerField(default=0) day = models.CharField(null=True,max_length=50,default=datetime.datetime.now().strftime("%Y-%m-%d")) hour =models.CharField(null=True,max_length=50,default=datetime.datetime.now().strftime("%H:%M:%S")) time = models.FloatField(null=True,default=time.time()) |
接受数据的接口views.py,这样我们的客户端上传上来的数据就已经能够存到数据库中了。
@csrf_exempt def getpingdata(request): if request.method == ‘POST‘: data=request.POST datamode =PingData(min=float(data[‘min‘]),max=float(data[‘max‘]),avg=float(data[‘avg‘]),sourceip=str(data[‘sourceip‘]),destip=str(data[‘destip‘]),loss=int(data[‘loss‘]),day=str(data[‘day‘]),hour=str(data[‘hour‘]),time=float(data[‘time‘])) datamode.save() return HttpResponse("OK") |
3、服务器页面展示
前端页面用bootstrap简单的做了个,通过ajax来请求后端web的接口然后在前端页面进行highchart画图。
3.1 jquery获取前端页面的数据,通过ajax POST给后端的api接口,其中我用了一个bootstrap的时间插件,这个插件用法可以自行查看文档。http://www.htmleaf.com/jQuery/Calendar-Date-Time-picker/201503041458.html
设定时间插件的显示格式
<script type="text/javascript">
$(function () {
$(‘#datetimepicker1‘).datetimepicker({
locale: ‘ru‘,
format:‘YYYY-MM-DD HH:m:s‘
});
$(‘#datetimepicker2‘).datetimepicker({
locale: ‘ru‘,
format:‘YYYY-MM-DD HH:m:s‘
});
});
</script>
3.2 通过jQuery+ajax+highcha来完成前端页面数据的获取提交,并从服务端请求数据,完成highchart的展示
timejs.html:
<div> <form> <div> <label for="sourceip">Source IP</label> <input type="text"id="sourceip" placeholder="eg:192.168.1.1" > </div> <div> <labelfor="destip">Dest IP</label> <input type="text"id="destip" placeholder="eg:192.168.1.1" > </div> <div> <label for="starttime">Start time</label> <div class=‘input-group date‘ id=‘datetimepicker1‘> <input type=‘text‘class="form-control" id="starttime"name="time" /> <spanclass="input-group-addon"><span></span></span> </div> </div> <div> <label for="endtime">End time</label> <div class=‘input-group date‘ id=‘datetimepicker2‘> <input type=‘text‘class="form-control" id="endtime"name="time" /> <spanclass="input-group-addon"><span></span></span> </div> </div> <button type="button" id="Goquery"class="btn btn-primarybtn-sm">查询</button> </form> </div> <div> <div id="container1"style="min-width:800px;height:400px"></div> <div id="container2"style="min-width:800px;height:400px"></div> </div> # 定义两个highchart对象. Highchart的话请参考此链接http://blog.csdn.net/splendid_java/article/details/9186681 <script> 在图中对应的是上方的图 function showMscChart(hour,max,min,avg){ $(‘#container1‘).highcharts({ chart: { type: ‘line‘, }, title: { text: ‘Network Responce‘ }, xAxis: { type:‘datetime‘, categories: hour #这边标示x坐标轴,我们通过参数hour来自定义 }, yAxis: { title: { text: ‘Network responce:ms‘ } }, plotOptions: { line: { dataLabels: { enabled: true }, enableMouseTracking: false } }, #series是具体需要显示的数据。我们同样通过传参来进行赋值。 series: [{ name: ‘max‘, data: max }, { name: ‘min‘, data: min }, { name: ‘avg‘, data: avg }] }); } #在显示的图中对应的是下方的图 function showLossChart(hour,loss){ $(‘#container2‘).highcharts({ chart: { type: ‘line‘, }, title: { text: ‘Network responce‘ }, xAxis: { type:‘datetime‘, categories: hour }, yAxis: { title: { text: ‘Network loss:%‘ } }, plotOptions: { line: { dataLabels: { enabled: true }, enableMouseTracking: false } }, series: [{ name: ‘loss‘, data: loss },] }); } </script> |
#当我们按查询的时候会触发这段js代码:(js代码更是现搜现用,忘大家帮改善)
<script> $("#Goquery").on("click",function(){ #从我们前端html页面中获取数据。 var Qureydata = {} Qureydata[‘starttime‘]=$(‘#datetimepicker1‘).data()[‘date‘] Qureydata[‘endtime‘]=$(‘#datetimepicker2‘).data()[‘date‘] Qureydata[‘sourceip‘]=$("#sourceip").val() Qureydata[‘destip‘]=$("#destip").val() //console.log(Qureydata) $.ajax({ type:"POST", url:"testping", #我们要提交的api接口的url dataType:"json", data:Qureydata, #我们提交的数据 success:function(data){ console.log(data) $.each(data,function(item,i){ if (item =="max"){max=i } if (item=="min"){min=i} if (item=="hour"){hour=i} if(item=="avg"){avg=i} if(item=="loss"){loss=i} }) #进行具体的highchart的实例化。 showMscChart(hour,max,min,avg) showLossChart(hour,loss) }, }) }) </script> |
基本上到此所有的功能就基本上都实现了。
4、部署Nginx+uwsgi
参考http://uwsgi-docs.readthedocs.org/en/latest/WSGIquickstart.html官网
或者自强学堂的部署文档也是很详尽简单,再次不多累述