一、项目背景与痛点
日常运维工作中,服务器状态巡检是保障业务稳定运行的核心工作。中小团队大多依赖人工定时登录服务器查看资源状态,大型运维监控平台又部署复杂、成本高昂,日常运维存在大量难以解决的痛点:
1.1 传统运维监控的痛点
- 人工巡检效率低下,无法7×24值守:运维人员需要早晚定时登录每台服务器,手动输入命令查看CPU、内存、磁盘、网络状态,夜间、节假日无人值守,故障无法第一时间发现;
- 故障发现滞后,极易引发业务雪崩:服务器内存溢出、磁盘爆满、核心进程挂掉、端口异常等问题,往往等到业务报错才被发现,故障持续时间长,影响线上业务稳定性;
- 商用监控平台太重,部署成本高:Prometheus+Grafana、Zabbix等专业监控组件部署繁琐、学习成本高,低配服务器无法承载,小团队没必要部署重型监控系统;
- 无历史数据留存,无法复盘故障:人工巡检无历史指标记录,服务器突发卡顿、负载飙升后,无法追溯之前的资源变化曲线,难以定位故障根因;
- 告警方式单一,无法及时触达运维:传统监控大多仅后台页面告警,运维人员不登录后台就无法感知故障,错过最佳故障处理时机。
1.2 项目解决方案
针对以上运维巡检痛点,本次基于Python系统监控库 + Django4.2后端框架,搭建轻量化服务器自动化监控巡检平台,依托psutil采集服务器硬件资源指标、进程状态、端口监控数据,搭配Celery定时任务实现分钟级自动巡检,支持后台可视化图表展示、异常阈值判定、邮件+钉钉机器人双渠道告警。
项目特点:
- 无需复杂中间件、部署零难度
- 完美适配中小团队单机/多服务器轻量化运维监控需求
- 补齐Django运维自动化实战方向
- 和往期所有项目无任何功能重合
二、核心目标与定位
2.1 核心目标
搭建轻量化、开箱即用的服务器无人值守监控系统,实现以下全流程自动化:
- 定时采集:服务器CPU/内存/磁盘/网络/进程/端口六大核心指标
- 指标入库存储:MySQL持久化存储历史监控数据
- 可视化展示:ECharts渲染实时趋势曲线
- 告警判定:自定义告警阈值智能判断
- 异常推送:多渠道实时告警通知
- 报表导出:自动生成每日巡检报告
最终效果:替代人工日常巡检,故障告警响应时间缩短至1分钟内。
2.2 项目定位
- 精准定位:轻量级单机/分布式服务器运维监控平台
- 技术理念:摒弃重型监控架构,纯Python原生psutil采集指标
- 部署优势:Django快速搭建管理后台,无需额外部署时序数据库
- 模式支持:支持单服务器本地监控、多服务器分布式监控两种模式
- 使用体验:运维人员可通过网页端随时查看服务器实时状态与历史走势
2.3 核心设计理念
- 轻量无依赖:最小化外部依赖,低配服务器也能稳定运行
- 定时自动采集:Celery实现无人值守定时巡检
- 可视化直观展示:ECharts图表直观展示资源变化趋势
- 异常多渠道告警:钉钉+邮件双渠道确保告警触达
- 历史数据可追溯:完整留存监控历史,支持故障复盘
三、整体技术方案
3.1 系统架构设计
项目采用Django MVT基础架构 + Celery定时任务,Python原生psutil库完成系统指标无侵入采集,前端ECharts渲染监控曲线图,整体分层架构如下:
#mermaid-svg-H1fW1OV03y9NoF8G{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-H1fW1OV03y9NoF8G .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-H1fW1OV03y9NoF8G .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-H1fW1OV03y9NoF8G .error-icon{fill:#552222;}#mermaid-svg-H1fW1OV03y9NoF8G .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-H1fW1OV03y9NoF8G .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-H1fW1OV03y9NoF8G .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-H1fW1OV03y9NoF8G .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-H1fW1OV03y9NoF8G .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-H1fW1OV03y9NoF8G .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-H1fW1OV03y9NoF8G .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-H1fW1OV03y9NoF8G .marker{fill:#333333;stroke:#333333;}#mermaid-svg-H1fW1OV03y9NoF8G .marker.cross{stroke:#333333;}#mermaid-svg-H1fW1OV03y9NoF8G svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-H1fW1OV03y9NoF8G p{margin:0;}#mermaid-svg-H1fW1OV03y9NoF8G .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-H1fW1OV03y9NoF8G .cluster-label text{fill:#333;}#mermaid-svg-H1fW1OV03y9NoF8G .cluster-label span{color:#333;}#mermaid-svg-H1fW1OV03y9NoF8G .cluster-label span p{background-color:transparent;}#mermaid-svg-H1fW1OV03y9NoF8G .label text,#mermaid-svg-H1fW1OV03y9NoF8G span{fill:#333;color:#333;}#mermaid-svg-H1fW1OV03y9NoF8G .node rect,#mermaid-svg-H1fW1OV03y9NoF8G .node circle,#mermaid-svg-H1fW1OV03y9NoF8G .node ellipse,#mermaid-svg-H1fW1OV03y9NoF8G .node polygon,#mermaid-svg-H1fW1OV03y9NoF8G .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-H1fW1OV03y9NoF8G .rough-node .label text,#mermaid-svg-H1fW1OV03y9NoF8G .node .label text,#mermaid-svg-H1fW1OV03y9NoF8G .image-shape .label,#mermaid-svg-H1fW1OV03y9NoF8G .icon-shape .label{text-anchor:middle;}#mermaid-svg-H1fW1OV03y9NoF8G .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-H1fW1OV03y9NoF8G .rough-node .label,#mermaid-svg-H1fW1OV03y9NoF8G .node .label,#mermaid-svg-H1fW1OV03y9NoF8G .image-shape .label,#mermaid-svg-H1fW1OV03y9NoF8G .icon-shape .label{text-align:center;}#mermaid-svg-H1fW1OV03y9NoF8G .node.clickable{cursor:pointer;}#mermaid-svg-H1fW1OV03y9NoF8G .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-H1fW1OV03y9NoF8G .arrowheadPath{fill:#333333;}#mermaid-svg-H1fW1OV03y9NoF8G .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-H1fW1OV03y9NoF8G .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-H1fW1OV03y9NoF8G .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-H1fW1OV03y9NoF8G .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-H1fW1OV03y9NoF8G .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-H1fW1OV03y9NoF8G .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-H1fW1OV03y9NoF8G .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-H1fW1OV03y9NoF8G .cluster text{fill:#333;}#mermaid-svg-H1fW1OV03y9NoF8G .cluster span{color:#333;}#mermaid-svg-H1fW1OV03y9NoF8G div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-H1fW1OV03y9NoF8G .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-H1fW1OV03y9NoF8G rect.text{fill:none;stroke-width:0;}#mermaid-svg-H1fW1OV03y9NoF8G .icon-shape,#mermaid-svg-H1fW1OV03y9NoF8G .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-H1fW1OV03y9NoF8G .icon-shape p,#mermaid-svg-H1fW1OV03y9NoF8G .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-H1fW1OV03y9NoF8G .icon-shape .label rect,#mermaid-svg-H1fW1OV03y9NoF8G .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-H1fW1OV03y9NoF8G .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-H1fW1OV03y9NoF8G .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-H1fW1OV03y9NoF8G :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 定时任务调度层
Celery分钟级巡检
系统指标采集层
psutil采集硬件指标
指标阈值判断层
匹配自定义告警阈值
数据持久化层
MySQL存储历史监控数据
可视化图表层
ECharts渲染趋势曲线
多渠道告警层
钉钉机器人+邮件告警
巡检报表导出层
自动生成每日巡检报告
3.2 技术栈清单
后端服务
- 开发语言:Python 3.11
- Web框架:Django 4.2 + Django原生后台管理
- 指标采集:psutil 原生Python系统监控库,无侵入采集服务器硬件资源
- 定时任务:Celery 5.2 + Redis 7.0,支持自定义巡检频率
- 数据存储:MySQL存储历史监控指标,Redis缓存实时最新监控数据
前端与可视化
- 数据可视化:ECharts 前端渲染CPU/内存/磁盘实时趋势折线图
- 报表生成:python-docx 自动生成每日服务器巡检Word报告
告警服务
- 即时通讯:钉钉自定义机器人Webhook推送
- 邮件通知:Python内置smtplib邮件告警服务
权限管控
- 用户管理:Django原生登录权限系统
- 角色区分:管理员和只读运维账号权限分离
四、核心能力模块详解
4.1 多维度服务器指标自动采集模块
基于psutil无侵入采集服务器全维度运行指标,无需安装服务器插件,兼容Windows和Linux双系统服务器,覆盖运维核心关注指标:
采集指标范围
- CPU指标:实时使用率、单核/多核负载、运行总时长
- 内存指标:总内存、已用内存、剩余内存、内存使用率
- 磁盘指标:磁盘总容量、已用容量、磁盘使用率、磁盘读写速率
- 网络指标:实时上行/下行网速、总收发流量
- 进程监控:核心业务进程存活状态、进程CPU/内存占用
- 端口监控:自定义业务端口存活检测,防止端口监听异常
4.2 自定义告警阈值配置模块
运维人员可在后台可视化配置各项指标告警红线,适配不同服务器硬件配置差异,无需修改代码即可调整告警规则:
告警配置策略
- 默认阈值:CPU使用率≥85%、内存使用率≥90%、磁盘使用率≥90%触发告警
- 进程告警:核心业务进程意外退出,立即触发紧急告警
- 告警防抖机制:短时间内连续异常仅推送一次告警,避免消息轰炸运维人员
- 告警分级:分为一般警告、严重故障两级,差异化推送告警文案
4.3 Celery无人值守定时巡检模块
依托Celery定时任务实现无人值守巡检,支持自由配置巡检频率,全程无需人工干预:
定时任务策略
- 高频实时巡检:1分钟一次采集核心资源指标,保证监控实时性
- 每日定点报表:每日凌晨自动生成昨日全天服务器巡检报告
- 历史数据自动清理:定时清理30天前过期监控数据,避免数据库数据堆积拖慢系统速度
4.4 前端可视化监控大盘模块
整合ECharts实现一站式监控大屏,直观展示服务器运行状态,告别枯燥命令行数据:
监控大屏功能
- 实时卡片展示:首页直观展示当前各项指标实时数值
- 趋势折线图:展示近1小时、近24小时CPU/内存波动曲线,快速定位资源峰值
- 告警日志面板:集中展示所有历史告警记录,包含告警时间、异常指标、恢复时间
- 服务器状态总览:一键查看所有接入服务器在线/离线状态
4.5 双渠道异常告警推送模块
打破后台告警局限,故障第一时间触达运维人员,保证夜间、节假日故障及时处理:
告警推送机制
- 钉钉机器人告警:服务器异常实时推送告警消息至运维钉钉群
- 邮件告警:同步发送详细故障邮件,附带故障时刻完整指标数据
- 故障恢复通知:服务器指标恢复正常后,自动推送恢复消息,形成告警闭环
4.6 自动化巡检报表模块
系统每日自动生成Word格式服务器巡检报告,包含全天指标均值、峰值、告警次数、故障时长,支持一键下载归档,满足运维每日工作汇报、机房巡检台账归档需求。
五、创新价值与亮点
5.1 技术优势对比
| 特性 | 传统监控平台 | 本项目方案 | 优势对比 |
|---|---|---|---|
| 部署复杂度 | 高(需部署时序数据库、中间件) | 低(纯Python+Django) | 部署简单,零门槛 |
| 资源消耗 | 高(占用大量服务器资源) | 低(1核2G即可运行) | 适合低配服务器 |
| 侵入性 | 高(需安装代理插件) | 无(psutil原生采集) | 无服务器侵入 |
| 告警渠道 | 单一(通常仅后台告警) | 双渠道(钉钉+邮件) | 告警触达率高 |
| 历史追溯 | 依赖额外配置 | 内置完整历史曲线 | 故障复盘方便 |
5.2 核心亮点
- 极致轻量化,低配服务器也能跑:对比Zabbix、Prometheus重型监控平台,本项目无复杂依赖、无时序数据库要求,1核2G低配服务器即可稳定运行,零部署门槛;
- 原生Python采集,无服务器侵入:依托psutil原生库采集数据,无需在被监控服务器安装代理插件,部署简单快捷;
- 双渠道告警,不漏任何故障:钉钉群实时弹窗+邮件详细报告双重告警,彻底解决运维人员看不到后台告警的痛点;
- 可视化趋势追溯,故障可复盘:完整留存历史监控曲线,能够精准复盘服务器卡顿、负载飙升的根因;
- 开箱即用免配置:内置默认告警阈值,部署即可直接使用,同时支持后台可视化自定义规则,适配各类业务服务器。
六、应用前景与落地场景
6.1 适用场景
- 中小研发团队线上服务器监控:替代人工日常巡检,7×24小时值守线上业务服务器,保障后端项目稳定运行;
- 个人云服务器运维监控:个人阿里云/腾讯云轻量服务器自用监控,及时发现服务器异常;
- 机房内网服务器统一巡检:内网批量接入多台服务器,统一大屏监控所有设备运行状态;
- Django运维自动化实战项目:补齐定时任务、系统运维采集、消息推送、数据可视化运维方向,区别于常规业务管理系统,简历项目亮点突出。
6.2 部署模式
单机监控模式
bash
# 单服务器本地监控部署
python manage.py runserver 0.0.0.0:8000
celery -A monitor_project worker --loglevel=info
分布式监控模式
bash
# 多服务器分布式监控
# 主控服务器运行Web服务
python manage.py runserver 0.0.0.0:8000
# 被监控服务器运行采集客户端
python client_collector.py --server-id=server001
七、完整代码结构示例
7.1 项目整体目录结构
bash
django-server-monitor/
├── manage.py
├── monitor_project/ # 项目全局配置目录
│ ├── settings.py # Celery定时任务、告警机器人、数据库配置
│ ├── urls.py # 前后端路由分发
│ └── celery.py # 定时任务全局初始化配置
├── apps/ # 模块化业务应用
│ ├── server_collect/ # 服务器指标采集核心模块
│ ├── alert_config/ # 告警阈值配置、告警日志模块
│ ├── message_push/ # 钉钉、邮件消息推送模块
│ ├── monitor_dashboard/ # ECharts可视化大盘模块
│ └── report_export/ # 自动巡检报表生成与下载模块
├── core/ # 公共工具封装
│ ├── system_collect.py # psutil系统指标采集工具类
│ ├── dingtalk_alert.py # 钉钉机器人告警工具
│ ├── email_alert.py # 邮件告警工具
│ └── monitor_task.py # Celery定时巡检主任务
├── static/ # ECharts图表静态资源
├── templates/ # 监控大盘前端页面模板
├── media/report/ # 自动生成的巡检报表存储目录
├── requirements.txt # Python项目依赖清单
└── docker-compose.yml # 一键容器化部署脚本
7.2 核心可运行代码片段
示例1:psutil服务器全指标采集工具类(core/system_collect.py)
python
import psutil
import time
class ServerMonitorCollect:
"""服务器硬件资源指标采集工具类"""
@staticmethod
def get_cpu_info():
"""获取CPU使用率与负载"""
cpu_percent = psutil.cpu_percent(interval=1)
load_avg = psutil.getloadavg()
return {
"cpu_percent": cpu_percent,
"load_1m": load_avg[0],
"load_5m": load_avg[1],
"load_15m": load_avg[2]
}
@staticmethod
def get_memory_info():
"""获取内存使用信息"""
mem = psutil.virtual_memory()
return {
"mem_total": round(mem.total / 1024 / 1024 / 1024, 2),
"mem_used": round(mem.used / 1024 / 1024 / 1024, 2),
"mem_percent": mem.percent
}
@staticmethod
def get_disk_info():
"""获取磁盘使用信息"""
disk = psutil.disk_usage('/')
return {
"disk_total": round(disk.total / 1024 / 1024 / 1024, 2),
"disk_used": round(disk.used / 1024 / 1024 / 1024, 2),
"disk_percent": disk.percent
}
@staticmethod
def get_net_info():
"""获取网络收发流量"""
net_before = psutil.net_io_counters()
time.sleep(1)
net_after = psutil.net_io_counters()
sent_speed = round((net_after.bytes_sent - net_before.bytes_sent) / 1024, 2)
recv_speed = round((net_after.bytes_recv - net_before.bytes_recv) / 1024, 2)
return {"sent_speed": sent_speed, "recv_speed": recv_speed}
@classmethod
def get_all_server_info(cls):
"""一次性获取全部服务器监控指标"""
return {
"cpu": cls.get_cpu_info(),
"memory": cls.get_memory_info(),
"disk": cls.get_disk_info(),
"network": cls.get_net_info(),
"collect_time": time.strftime("%Y-%m-%d %H:%M:%S")
}
示例2:Celery定时巡检主任务(core/monitor_task.py)
python
from celery import shared_task
from core.system_collect import ServerMonitorCollect
from core.dingtalk_alert import DingTalkAlert
from apps.alert_config.models import AlertThreshold, AlertLog
from django.utils import timezone
# 读取后台配置的告警阈值
THRESHOLD = AlertThreshold.objects.first()
@shared_task
def server_auto_monitor_task():
"""Celery定时服务器巡检主任务"""
# 1. 采集全量服务器指标
monitor_data = ServerMonitorCollect.get_all_server_info()
cpu_per = monitor_data["cpu"]["cpu_percent"]
mem_per = monitor_data["memory"]["mem_percent"]
disk_per = monitor_data["disk"]["disk_percent"]
# 2. 阈值判断,触发告警
alert_msg = ""
if cpu_per >= THRESHOLD.cpu_threshold:
alert_msg += f"【CPU异常】当前CPU使用率:{cpu_per}%,超过告警阈值{THRESHOLD.cpu_threshold}%\n"
if mem_per >= THRESHOLD.mem_threshold:
alert_msg += f"【内存异常】当前内存使用率:{mem_per}%,超过告警阈值{THRESHOLD.mem_threshold}%\n"
if disk_per >= THRESHOLD.disk_threshold:
alert_msg += f"【磁盘异常】当前磁盘使用率:{disk_per}%,超过告警阈值{THRESHOLD.disk_threshold}%\n"
# 3. 存在异常则推送钉钉告警并写入告警日志
if alert_msg:
full_msg = f"⚠️服务器监控告警通知\n告警时间:{timezone.now()}\n异常详情:\n{alert_msg}"
DingTalkAlert.send_message(full_msg)
# 写入告警日志
AlertLog.objects.create(
alert_content=alert_msg,
alert_level="严重故障",
alert_status="未恢复"
)
return {"status": "alert", "msg": "服务器存在资源异常,已推送告警消息"}
return {"status": "normal", "msg": "服务器运行状态正常"}
示例3:钉钉机器人消息推送工具(core/dingtalk_alert.py)
import
class DingTalkAlert:
"""钉钉机器人消息推送工具"""
# 替换为自己的钉钉机器人Webhook地址
DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=xxxxxxx"
@staticmethod
def send_message(content: str):
"""发送文本告警消息至钉钉群"""
headers = {"Content-Type": "application/json"}
data = {
"msgtype": "text",
"text": {
"content": content
}
}
try:
res = requests.post(DingTalkAlert.DING_WEBHOOK, json=data, headers=headers, timeout=5)
return res.json()
except Exception as e:
print(f"钉钉消息推送失败:{str(e)}")
return None
八、总结与展望
本篇博客基于Python+Django+psutil打造轻量化服务器自动化监控平台,聚焦运维自动化赛道,和往期笔记系统、校园商城、AI图像处理、代码评审等业务类、AI类项目完全区分,填补了Django运维监控实战项目的空白。
项目完整覆盖Python系统运维采集、Celery定时任务调度、第三方消息接口对接、ECharts数据可视化、告警日志台账管理、自动化报表生成六大核心后端能力,代码通俗易懂、业务逻辑贴合真实运维工作,既可以直接部署用于线上服务器值守,也能作为简历中差异化极强的后端实战项目,避开烂大街的商城、管理系统项目。