最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台

栏目: Python · 发布时间: 6年前

内容简介:今天我们将编写功能模块,并在代码开始之前对功能模块进行分析,并通过流程图和 UML 类图的绘制将模块功能细化,接着从搭建骨架开始,逐步完成一个模块的编写。已经可以启动一个 Web 页面了,并且已经通过 MongoEngine 定义了一个 ORM。接下来我们应该对每个模块功能进行编写,并且为每个编写好的模块编写视图。思考:在多个模块当中,

今天我们将编写功能模块,并在代码开始之前对功能模块进行分析,并通过流程图和 UML 类图的绘制将模块功能细化,接着从搭建骨架开始,逐步完成一个模块的编写。

最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台
经过之前的学习 《 Python 系统资源信息获取工具,你用过没?》、 《【一】从0开始,用flask+mongo打造分布式服务器监控平台》召唤师峡谷萌新

已经可以启动一个 Web 页面了,并且已经通过 MongoEngine 定义了一个 ORM。接下来我们应该对每个模块功能进行编写,并且为每个编写好的模块编写视图。

模块编写顺序

思考:在多个模块当中, 萌新 应该先完成哪一个模块呢?

我们给需求进行排序,看看他们各自的权重和依赖关系,回顾一下我们需要编写的模块:

  • 数据处理与可视化
  • 信息监控
  • 警报模块
  • 数据存储
  • API 视图

奎因画了一张图,从这张图上我们就可以看出每个模块的依赖和作用:

最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台

首先应该先读取每台服务器的资源,在读取资源的时候检查是否超过阈值,然后主机一次性获取所有服务器资源信息并存入数据库,接着出库计算并将数据处理成可视化图表。所以可以将上面的模块编写顺序做一下调整:

  • 信息监控
  • 数据存储
  • 数据处理与可视化

至于剩下的警报模块和 API 视图,在前三个模块开发过程中用于调试,可以只保留逻辑占位(也就是 python 中常用的 Pass)待前三个模块开发完成后再回头补充警报模块和 API 视图的逻辑即可。

信息监控模块的实现

最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台

《Python 系统资源信息获取工具,你用过没?》 中,我们已经学会了(非 windows)服务器资源信息的获取,现在我们需要将之前所学的知识转化成为功能模块,也就是在代码中通过类来实现资源信息获取,这样我们就可以通过类的实例化和方法调用的方式获取的所需的数据。

思考:在弄清楚需求、作用之后,我们就可以开始编写代码了吗?

如果你是一名经验丰富的开发者,想必你心中已经有了代码的一个大致结构。但是作为萌新,我们还没能够那么快在脑海中生成结构,所以我们还是需要画图。在代码开始前进行构思、画图可以让萌新们减少错误、同时也减少代码的改动次数,有一定的几率提升,既然现在是编写类,那么我们就来绘制一个 UML 类图吧!

首先,我们应该给类想一个名字,就叫 PresentMomentSystemResource 吧,所以一个空的 UML 图就可以画出来了:

最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台

至于里面的方法,我们想一下:

  • 应该有一个 init 方法,这样就可以在类实例化的时候指定一些类变量;
  • 对于 cpu、内存硬盘以及进程的数据,应该有不同的方法进行获取;
  • 考虑到这个类可能会被多次实例化,在多个地方被调用,那么就有可能需要使用单例模式;

所以 UML 图改动一下:

最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台

奎因给大家解释一下这个 UML 类图的含义:

  • 魔术方法 new 来完成类单例模式
  • 魔术方法 init 设定实例化时使用的一些类变量
  • 接下来给每个硬件信息数据定义一个方法,并且的到的结果都以 dict 的数据类型返回

然后我们就可以开始代码的编写了。

对于这一次的项目,我们新建一个文件夹 Monitors,然后再在里面新建一个 python package 名字叫 monitors,接着在项目内新建一个名为core.py 的文件,结构如下图所示:

最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台

并且根据 UML 类图编写类的基础结构:

# 崔庆才丨静觅、韦世东丨奎因 邀请你关注微信公众号【进击的Coder】和大佬一起coding 共同进步
class PresentMomentSystemResource:

    def __new__(cls, *args, **kwargs):
        # singleton
        pass

    def __init__(self):
        pass

    def memory_usage(self):
        """当前时刻内存用量信息
        """
       pass

    def cpu_usage(self):
        """ 当前时刻cpu用量信息 """
        pass

    def disks_usage(self):
        """ 当前时刻根目录磁盘用量信息 """
        pass

    def processes_id(self):
        """ 筛选当前时刻关键字相关的pid列表及数量 """
        pass

复制代码

搭好类的骨架之后,我们就来为每个方法编写实际的代码。

首先,我们用魔术方法 new 将类变成单例模式,所以 new 方法部分的代码改为:

def __new__(cls, *args, **kwargs):
        # singleton
        if not hasattr(cls, '_instance'):
            cls._instance = super(PresentMomentSystemResource, cls).__new__(cls, *args, **kwargs)
        return cls._instance
复制代码

作为老司机,应该是可以在编写完代码开始下一个方法的编写。但是现在我们是 召唤师峡谷的萌新 ,对不对?那 萌新 肯定是不知道自己写的代码是否正确,所以我们需要编写测试代码,只要确定类实例化后确实只有一个实例对象,那么就可以进行下一步了。

所以我们还需要新建一个测试文件testing.py,并在里面编写:

from monitors.core import PresentMomentSystemResource


if __name__ == "__main__":
    p1 = PresentMomentSystemResource()
    p2 = PresentMomentSystemResource()
    print(p1, p2)
复制代码

运行testing.py 文件,我们看一看控制台的输出内容:

<monitors.core.PresentMomentSystemResource object at 0x7fb0862a7128>
<monitors.core.PresentMomentSystemResource object at 0x7fb0862a7128>

Process finished with exit code 0
复制代码

由输出结果得知,p1 和 p2 是同一个实例对象,说明 new 方法实现单例模式奏效了。

接着我们来编写下一个方法。在之前的文章 《Python 系统资源信息获取工具,你用过没?》 中提到过可以获取系统资源信息的 psutil ,并且知道获取 cpu 信息、内存信息以及磁盘信息所用的方法,所以我们可以在 init 方法中将这几个方法初始化:

import psutil

    def __init__(self):
        self.memory = psutil.virtual_memory()
        self.cpu = psutil.cpu_times()
        self.disk = psutil.disk_usage("/")
复制代码

其中关于磁盘部分的信息,我们制定获取 "/" 盘符信息即可,其他挂载磁盘信息并没有那么重要。

获取到的数值单位为k,但是通常情况下我们使用的单位是 M 或者 G ,这里还需要设定两个单位:

from math import pow

    def __init__(self):
        self.memory = psutil.virtual_memory()
        self.cpu = psutil.cpu_times()
        self.disk = psutil.disk_usage("/")
        self.mb = pow(1024, 2)
        self.gb = pow(1024, 3)

复制代码

pow 方法是 python 内置库中用于计算幂的方法,可以计算某个数值 m 的 n 次幂,也就是可以将它理解为:

pow(m, n) = m 的n 次方。

到了真正编写每个硬件资源信息代码的时候了,我们首先来看看内存。内存需要的信息为内存总量、已使用量、剩余量及剩余百分比。我们从之前的文章可以知道,通过上面定义的 self.memory 就可以直接取到部分内存的用量信息:

def memory_usage(self):
        """当前时刻内存用量信息
        """
        total = self.memory.tota
        used = self.memory.used
     
复制代码

psutil 并没有给我们提供直接获取余量和余量百分比,所以我们在将数值单位计算完毕后,可以用数学运算计算出余量和余量百分比,此处 memory_usage 代码改为:

def memory_usage(self):
        """当前时刻内存用量信息
        """
        total = self.memory.total/self.gb
        used = self.memory.used/self.gb
        free = total - used
        percent = round(free/total, 2)
        return total, used, free, percent
复制代码

然后到testing.py 中测试一下:

from monitors.core import PresentMomentSystemResource


if __name__ == "__main__":
    p1 = PresentMomentSystemResource()
    res = p1.memory_usage()
    print(res)
复制代码

运行后得到的输出结果为:

(7.676643371582031, 1.7717132568359375, 5.904930114746094, 0.77)
复制代码

跟系统自带的系统资源监控做个比对:

最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台

总体上是吻合的,说明这种方法取值和计算是没有问题的。

然后按照之前的文章和这样的方法,编写其他几个硬件的代码,最后整个core.py 文件的代码为:

import psutil
from math import pow
from functools import reduce


class PresentMomentSystemResource:

    def __new__(cls, *args, **kwargs):
        # singleton
        if not hasattr(cls, '_instance'):
            cls._instance = super(PresentMomentSystemResource, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    def __init__(self):
        self.memory = psutil.virtual_memory()
        self.cpu = psutil.cpu_times()
        self.disk = psutil.disk_usage("/")
        self.mb = pow(1024, 2)
        self.gb = pow(1024, 3)

    @property
    def memory_usage(self):
        """当前时刻内存用量信息
        """
        total = self.memory.total/self.gb
        used = self.memory.used/self.gb
        free = total - used
        percent = round(free/total, 2)
        buffers = self.memory.buffers/self.gb
        cached = self.memory.cached/self.gb
        total, used, free, buffers, cached = map(lambda x: round(x, 2), [total, used, free, buffers, cached])
        return {"total": total, "used": used, "free": free, "free_percent": percent, "buffers": buffers, "cached": cached}

    @property
    def cpu_usage(self):
        """ 当前时刻cpu用量信息 """
        count = psutil.cpu_count()
        logical_count = psutil.cpu_count(logical=True)
        percent = psutil.cpu_percent(interval=1)
        return {"count": count, "logical_count": logical_count, "percent": percent}

    @property
    def disks_usage(self):
        """ 当前时刻根目录磁盘用量信息 """
        total, used, free = map(lambda x: round(x/self.gb), self.disk[:3])
        percent = self.disk.percent
        return {"total": total, "used": used, "free": free, "free_percent": percent}

    def processes_id(self, keywords=['python']):
        """ 筛选当前时刻关键字相关的pid列表及数量 """
        attrs = psutil.process_iter(attrs=['pid', 'name'])
        pid = [[p.info for p in attrs if keyword in p.info['name']] for keyword in keywords]
        pid_number = reduce(lambda x, y: x+y, [len(p) for p in pid])
        return {"pid": pid, "type_number": len(pid), "pid_number": pid_number}

复制代码

这里着重说明一下:由于我们的监控是针对爬虫与服务器资源关系的监控,所以 processes_id 方法限定进程 id 的获取仅获取 Python 相关的进程。

flask 视图编写

有了信息获取,那么我们来试试,如何在 flask 中使用这个类。

首先,我们在 monitors 的init.py 文件中设置好 flask

from flask import Flask
from flask.ext.restful import Resource, Api

app = Flask(__name__)
api = Api(app)
resource = Resource
复制代码

然后新建一个start.py 文件,并像之前的文章一样将 flask 的骨架搭好

(在此之前请在电脑的 python 环境中安装 flask、flask-restful):

# start.py
from monitors import app, api, resource

class PresentMomentSystemResourceView(resource):
    """ 当前时刻系统资源占用信息视图 """
    def __init__(self):
        pass

    def get(self):
        
        return {"status": "success", "message": "this is flask view"}

api.add_resource(PresentMomentSystemResourceView, '/')

if __name__ == '__main__':
    app.run(debug=False)

复制代码

接着运行start.py 文件,得到输出:

from flask.ext.restful import Resource, Api
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

复制代码

说明我们可以通过浏览器访问本机的 5000 端口:

最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台

这里返回的内容就是刚才编写的试图时 return 的内容,说明 flask 的视图骨架搭好了。下一步则是将系统资源信息获取类与视图类相关联,将 start .py 的代码改为:

# start.py
from monitors import app, api, resource
from monitors.core import PresentMomentSystemResource


class PresentMomentSystemResourceView(resource):
    """ 当前时刻系统资源占用信息视图 """
    def __init__(self):
        self.sr = PresentMomentSystemResource()

    def get(self):
        memory = self.sr.memory_usage
        disks = self.sr.disks_usage
        cpu = self.sr.cpu_usage
        pid = self.sr.processes_id()
        return {"cpu": cpu, "memory": memory, "disk": disks, "pid": pid}

复制代码

在运行start.py 文件后,我们刷新刚才浏览器的页面,得到一串数据(火狐浏览器自动格式化,其他浏览器的数据显示可能没有那么整齐):

最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台

这些数据就是我们在视图类中 return 的 cpu、内存、磁盘以及进程信息数据。

至此,我们 德玛西亚阵营 的服务器信息获取模块就编写完成,下一次我们将会编写数据存储以及其他的模块。

小结

(文中所用代码和流程图、UML 类图等,关注微信公众号【进击的Coder】后,在微信公众号发送 "最佳实践二" 即可获得下载地址)

今天你在 召唤师峡谷 学习到的并不止是模块的编写和 flask 的基本代码编写, 更重要的是学会了如何分析模块的构成、通过绘制流程图和 UML 类图对自己所编写的模块进行细化,最终实现了了一个独立的模块。作为 召唤师峡谷的萌新 ,你体会到 奎因 今天的用意了吗?

最佳实践【二】从 0 开始,用 flask+mongodb 打造分布式服务器监控平台

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

颠覆式成长

颠覆式成长

惠特尼•约翰逊 / 张瀚文 / 中信出版集团 / 2018-8 / 49.00

你可能想要标新立异、挑战自我,甚至抛弃安逸的事业; 你可能会从目前的行业或公司中跳槽,进入一个完全陌生的崭新领域, 这本书会让你认识到颠覆式成长的意义所在。 成功没有捷径,颠覆也会令人心生惧意,但是在职业发展与个人成长上的回报,会让你克服这种恐惧,让你不断尝试、不断精进。 S型曲线精进模型将帮助你预测自己创新的成长周期,洞悉颠覆自我过程中的心路历程,在变革与颠覆中从容应对,......一起来看看 《颠覆式成长》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具