我尽量长话短说,大家能理解中心思想即可。

事件背景

  公司有国际业务,现有数据中心在UCLOUD 香港,国内和香港的网络掉包严重。所以考虑换数据中心,于是要测现有国内外服务器和供选择的新数据中心的网络情况。主要测试网络时延和丢包情况。这可能有现有工具(如果你们知道请评论留言)1是我懒得去弄zabbixzabbix应该是可以通过UserParams来收集各个节点到指定IP的网络情况。2主要是我想练一下django,试一下highchart怎么用。因为我本身web前端都不在行,平常都弄运维了。所以就有自己写这件事情。

 

技术思路

  各个节点的服务器运行一个agent.py进行网络情况的收集,并把数据通过web api POSTweb服务器上。Web服务器使用django提供一个收集数据的api,另外提供一个简单的查询页面,把取出的数据用highchart画图。  这个逻辑很简单。最终画出的图是这样的:

wKioL1ZX7OGD9iZ3AADk4ifmJbw622.png

开发前的环境部署:

  Server ubuntu,django 1.8 ,python 2.7 


技术关键点

  我们从agentweb数据收集,到图形展示的顺序来讲:

   1agent数据收集,上传。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

静态模板设置:

wKiom1ZX7gbiOOWLAAAle1sbQMw941.png

数据库设置:

wKioL1ZX7nygXK2jAAAfdOaqNHI834.png

#进行数据库同步

#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 

#这些字段都很好理解,IPping的数据,agent数据的采集时间点。(分为日期,时间,时间戳)具体出现的datatimetime大家自行实践都能明白。

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

wKioL1ZX70ySNeL5AAAlVLz3mzc447.png

设定时间插件的显示格式

   <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官网

或者自强学堂的部署文档也是很详尽简单,再次不多累述