基于 Vue3 + Node.js 的实时可视化监控系统实现

目录

  • [ServWatch:基于 Vue3 + Node.js 的实时可视化监控系统实现](#ServWatch:基于 Vue3 + Node.js 的实时可视化监控系统实现)
    • 前言
    • 一、系统架构
      • [1.1 整体架构图](#1.1 整体架构图)
      • [1.2 技术栈选型](#1.2 技术栈选型)
    • 二、核心功能实现
      • [2.1 实时监控仪表板](#2.1 实时监控仪表板)
      • [2.2 监控数据可视化](#2.2 监控数据可视化)
      • [2.3 告警规则引擎](#2.3 告警规则引擎)
      • [2.4 指标采集 Agent](#2.4 指标采集 Agent)
    • [三、API 设计](#三、API 设计)
      • [3.1 RESTful API](#3.1 RESTful API)
      • [3.2 认证机制](#3.2 认证机制)
    • 四、快速部署
      • [4.1 模拟模式(最快体验)](#4.1 模拟模式(最快体验))
      • [4.2 Docker Compose 部署](#4.2 Docker Compose 部署)
      • [4.3 本地开发部署](#4.3 本地开发部署)
    • 五、项目结构
    • 六、界面预览
      • [6.1 登录页面](#6.1 登录页面)
      • [6.2 GPU 监控](#6.2 GPU 监控)
      • [6.3 监控目标管理](#6.3 监控目标管理)
    • 七、后续规划
    • 八、总结

ServWatch:基于 Vue3 + Node.js 的实时可视化监控系统实现

前言

在日常运维和开发工作中,服务器监控是必不可少的环节。市面上有不少优秀的监控方案(如 Prometheus、Grafana、Zabbix 等),但对于中小型团队或个人开发者来说,这些工具往往过于复杂,学习成本较高。

本文将介绍我自己开发的 ServWatch 监控系统------一个轻量级、易部署、界面美观的实时监控解决方案。


一、系统架构

1.1 整体架构图

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                         ServWatch 系统架构                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                   │
│  ┌──────────────┐      ┌──────────────┐      ┌──────────────┐  │
│  │              │      │              │      │              │  │
│  │   Browser    │◄────►│  Frontend    │◄────►│   Backend    │  │
│  │              │ WS   │  Vue 3 +     │ HTTP │  Node.js     │  │
│  │              │      │  ECharts     │      │  Express     │  │
│  └──────────────┘      └──────────────┘      └──────┬───────┘  │
│                                                      │          │
│                                              ┌───────▼───────┐  │
│  ┌──────────────┐      ┌──────────────┐      │   Postgres   │  │
│  │              │      │              │      │  TimescaleDB │  │
│  │    Agent     │─────►│   Redis      │─────►│              │  │
│  │   采集器     │ HTTP │   缓存        │      │   时序数据   │  │
│  │              │      │              │      │              │  │
│  └──────────────┘      └──────────────┘      └──────────────┘  │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

1.2 技术栈选型

层级 技术选型 理由
前端框架 Vue 3 Composition API 开发体验好
构建工具 Vite 开发速度快,HMR 体验优秀
状态管理 Pinia Vue 3 官方推荐,API 简洁
UI 组件 Element Plus 组件丰富,文档完善
图表库 Apache ECharts 图表功能强大,交互性好
后端框架 Express 轻量灵活,中间件丰富
实时通信 Socket.IO WebSocket 封装,兼容性好
数据库 PostgreSQL + TimescaleDB 关系型 + 时序数据扩展
缓存 Redis 高性能 KV 存储

二、核心功能实现

2.1 实时监控仪表板

仪表板是监控系统的核心界面,展示所有监控目标的整体状态。

WebSocket 实时推送实现:

javascript 复制代码
// 前端:建立 WebSocket 连接
import { io } from 'socket.io-client'

const socket = io('http://localhost:3001', {
  auth: { token: localStorage.getItem('token') }
})

// 注册为仪表板客户端
socket.emit('dashboard:connect')

// 订阅实时指标
socket.emit('metrics:subscribe', { targetIds: ['1', '2', '3'] })

// 接收实时更新
socket.on('metrics:update', (data) => {
  console.log('实时指标:', data)
  // 更新图表数据
})
javascript 复制代码
// 后端:WebSocket 服务
class WebSocketService {
  constructor(io) {
    this.io = io
    this.dashboardClients = new Set()
    this.setupEventHandlers()
  }

  setupEventHandlers() {
    this.io.on('connection', (socket) => {
      socket.on('dashboard:connect', () => {
        this.dashboardClients.add(socket.id)
        socket.emit('dashboard:connected', { clientId: socket.id })
      })

      socket.on('metrics:subscribe', ({ targetIds }) => {
        socket.join(`metrics:${targetIds.join(',')}`)
      })

      socket.on('disconnect', () => {
        this.dashboardClients.delete(socket.id)
      })
    })
  }

  // 推送实时指标到所有仪表板客户端
  broadcastMetrics(targetId, metrics) {
    this.io.emit('metrics:update', {
      targetId,
      metrics,
      timestamp: new Date().toISOString()
    })
  }

  // 推送告警通知
  broadcastAlert(alert, value) {
    this.io.emit('alert:triggered', {
      alert,
      value,
      timestamp: new Date().toISOString()
    })
  }
}

2.2 监控数据可视化

使用 ECharts 实现实时折线图:

vue 复制代码
<template>
  <div ref="chartRef" style="width: 100%; height: 300px"></div>
</template>

<script setup>
import { ref, onMounted, watch } from 'vue'
import * as echarts from 'echarts'

const chartRef = ref(null)
let chart = null

const initChart = () => {
  chart = echarts.init(chartRef.value)
  chart.setOption({
    title: { text: 'CPU 使用率' },
    tooltip: { trigger: 'axis' },
    xAxis: {
      type: 'category',
      data: []
    },
    yAxis: {
      type: 'value',
      max: 100,
      axisLabel: { formatter: '{value}%' }
    },
    series: [{
      name: 'CPU',
      type: 'line',
      smooth: true,
      data: [],
      areaStyle: {
        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
          { offset: 0, color: 'rgba(64, 158, 255, 0.5)' },
          { offset: 1, color: 'rgba(64, 158, 255, 0.1)' }
        ])
      }
    }]
  })
}

// 实时更新图表数据
const updateChart = (timestamp, value) => {
  const option = chart.getOption()
  option.xAxis[0].data.push(timestamp)
  option.series[0].data.push(value)

  // 保持最近 60 个数据点
  if (option.xAxis[0].data.length > 60) {
    option.xAxis[0].data.shift()
    option.series[0].data.shift()
  }

  chart.setOption(option)
}

onMounted(() => {
  initChart()

  // 监听 WebSocket 数据更新
  socket.on('metrics:update', ({ metrics }) => {
    updateChart(new Date().toLocaleTimeString(), metrics.cpu)
  })
})
</script>

2.3 告警规则引擎

告警评估服务实现:

javascript 复制代码
class AlertService {
  constructor() {
    this.alertRules = new Map()
    this.alertHistory = []
    this.cooldowns = new Map()
  }

  // 添加告警规则
  addRule(rule) {
    this.alertRules.set(rule.id, rule)
  }

  // 评估指标是否触发告警
  async evaluate(targetId, metricType, value) {
    const rules = Array.from(this.alertRules.values())
      .filter(r => r.targetId === targetId && r.metricType === metricType && r.enabled)

    for (const rule of rules) {
      const shouldAlert = this.checkCondition(value, rule)

      if (shouldAlert && !this.isInCooldown(rule.id)) {
        await this.triggerAlert(rule, value)
        this.setCooldown(rule.id, rule.cooldown || 300)
      }
    }
  }

  // 检查条件
  checkCondition(value, rule) {
    switch (rule.condition) {
      case 'greater_than':
        return value > rule.threshold
      case 'less_than':
        return value < rule.threshold
      case 'equals':
        return value === rule.threshold
      default:
        return false
    }
  }

  // 触发告警
  async triggerAlert(rule, value) {
    const alertHistory = {
      id: generateId(),
      alertId: rule.id,
      alertName: rule.name,
      severity: rule.severity,
      status: 'active',
      message: `${rule.name}触发: 当前值 ${value}, 阈值 ${rule.threshold}`,
      value,
      threshold: rule.threshold,
      createdAt: new Date().toISOString()
    }

    this.alertHistory.push(alertHistory)
    rule.triggerCount++

    // 通知 WebSocket 客户端
    websocketService.broadcastAlert(rule, value)

    // TODO: 发送邮件/钉钉通知
  }

  isInCooldown(ruleId) {
    const cooldownEnd = this.cooldowns.get(ruleId)
    return cooldownEnd && Date.now() < cooldownEnd
  }

  setCooldown(ruleId, seconds) {
    this.cooldowns.set(ruleId, Date.now() + seconds * 1000)
  }
}

2.4 指标采集 Agent

Agent 负责在被监控服务器上采集系统指标:

javascript 复制代码
const os = require('os')
const axios = require('axios')

class SystemCollector {
  constructor(config) {
    this.interval = config.collectInterval || 1000
  }

  // 采集 CPU 指标
  collectCPU() {
    const cpus = os.cpus()
    const totalIdle = cpus.reduce((acc, cpu) => acc + cpu.times.idle, 0)
    const totalTick = cpus.reduce((acc, cpu) => {
      return acc + Object.values(cpu.times).reduce((a, b) => a + b, 0)
    }, 0)

    return {
      usage: ((1 - totalIdle / totalTick) * 100).toFixed(2),
      cores: cpus.map(cpu => ({
        usage: ((1 - cpu.times.idle / Object.values(cpu.times).reduce((a, b) => a + b, 0)) * 100).toFixed(2)
      }))
    }
  }

  // 采集内存指标
  collectMemory() {
    const total = os.totalmem()
    const free = os.freemem()
    const used = total - free

    return {
      total: (total / 1024 / 1024 / 1024).toFixed(2), // GB
      used: (used / 1024 / 1024 / 1024).toFixed(2),
      free: (free / 1024 / 1024 / 1024).toFixed(2),
      usage: ((used / total) * 100).toFixed(2)
    }
  }

  // 采集网络指标
  async collectNetwork() {
    const stats = await getNetworkStats()
    return {
      rx: stats.rx, // bytes/s
      tx: stats.tx
    }
  }

  // 采集所有指标
  async collectAll() {
    return {
      cpu: this.collectCPU(),
      memory: this.collectMemory(),
      network: await this.collectNetwork(),
      disk: await this.collectDisk(),
      timestamp: new Date().toISOString()
    }
  }
}

// 定时采集并发送
const collector = new SystemCollector(config)
const transmitter = new HttpTransmitter(config.serverUrl)

setInterval(async () => {
  const metrics = await collector.collectAll()
  await transmitter.send(metrics)
}, collector.interval)

三、API 设计

3.1 RESTful API

分类 端点 方法 说明
认证 /auth/login POST 用户登录
认证 /auth/register POST 用户注册
认证 /auth/refresh POST 刷新 Token
目标 /targets GET 获取所有监控目标
目标 /targets POST 创建监控目标
目标 /targets/:id PUT 更新监控目标
告警 /alerts GET 获取告警规则
告警 /alerts POST 创建告警规则
指标 /metrics/realtime GET 获取实时指标
指标 /metrics/aggregated GET 获取聚合指标
统计 /stats/overview GET 系统概览统计

3.2 认证机制

使用 JWT Bearer Token 认证:

javascript 复制代码
// 登录获取 Token
POST /auth/login
{
  "identifier": "admin",
  "password": "admin123"
}

// 响应
{
  "user": { "id": "1", "username": "admin", ... },
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

// 使用 Token 访问 API
GET /targets
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

四、快速部署

4.1 模拟模式(最快体验)

无需后端,直接体验前端界面:

bash 复制代码
cd frontend
npm install
npm run dev -- --port 5175

# 访问 http://localhost:5175
# 登录账号: admin / admin123

4.2 Docker Compose 部署

一键启动所有服务:

bash 复制代码
docker-compose -f docker/docker-compose.yml up -d

# 服务列表:
# - Frontend:  http://localhost:5173
# - Backend:   http://localhost:3001
# - PostgreSQL: localhost:5432
# - Redis:     localhost:6379

4.3 本地开发部署

bash 复制代码
# 1. 启动数据库
docker run -d --name servwatch-postgres \
  -e POSTGRES_DB=servwatch \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=postgres \
  -p 5432:5432 \
  timescale/timescaledb:latest-pg16

# 2. 启动后端
cd backend
npm install
npm run dev

# 3. 启动前端
cd frontend
cp .env.production .env
npm install
npm run dev -- --port 5175

# 4. (可选) 启动 Agent
cd agent
npm install
npm start

五、项目结构

复制代码
ServWatch/
├── backend/                    # Node.js 后端服务
│   ├── src/
│   │   ├── config/            # 配置管理
│   │   ├── controllers/       # 请求处理器
│   │   ├── services/          # 业务逻辑
│   │   │   ├── websocketService.js   # WebSocket连接管理
│   │   │   ├── alertService.js       # 告警评估通知
│   │   │   └── metricsService.js     # 指标聚合处理
│   │   ├── models/            # 数据模型
│   │   ├── routes/            # API路由
│   │   ├── websocket/         # WebSocket处理器
│   │   └── app.js
│   └── package.json
│
├── agent/                      # 指标采集代理
│   ├── src/
│   │   ├── collectors/        # 采集器
│   │   │   ├── systemCollector.js   # 系统指标
│   │   │   ├── appCollector.js      # 应用指标
│   │   │   └── apiCollector.js      # API性能
│   │   ├── transmitters/      # 数据传输
│   │   └── agent.js
│   └── package.json
│
├── frontend/                   # Vue.js 前端
│   ├── src/
│   │   ├── components/        # Vue组件
│   │   ├── composables/       # 组合式函数
│   │   ├── stores/            # Pinia状态管理
│   │   ├── services/          # API服务
│   │   └── views/             # 页面视图
│   └── package.json
│
└── docker/                     # Docker 配置
    └── docker-compose.yml

六、界面预览

6.1 登录页面

6.2 GPU 监控

6.3 监控目标管理


七、后续规划

  • 基础框架搭建
  • 系统指标采集
  • 应用性能监控
  • 告警系统
  • WebSocket 实时通信
  • Docker 容器化
  • 邮件/钉钉通知功能
  • 自定义仪表板
  • 数据导出报表
  • 多租户支持
  • 移动端适配

八、总结

ServWatch 是一个功能完整、易于部署的监控系统。相比 Prometheus+Grafana 组合,它更加轻量,学习成本更低,适合中小型团队和个人开发者使用。

如果你正在寻找一个简洁、美观的服务器监控方案,不妨试试 ServWatch!

GitHub项目地址1 : https://github.com/Anthony-981/ServWatch

Gitee项目地址2 : https://gitee.com/an-xuhui231/serv-watch

欢迎 Star 和 Fork,有问题欢迎提 Issue!

版权声明:本文为原创文章,转载请注明出处。

相关推荐
说给风听.7 小时前
解决 Node.js 版本冲突:Windows 系统 nvm 安装与使用全指南
windows·node.js
森叶11 小时前
Node.js 跨进程通信(IPC)深度进阶:从“杀人”的 kill 到真正的信号
node.js·编辑器·vim
虹科网络安全1 天前
艾体宝新闻 | NPM 生态系统陷入困境:自我传播恶意软件在大规模供应链攻击中感染了 187 个软件包
前端·npm·node.js
摇滚侠1 天前
PNPM 包管理工具和 NPM 包管理工具
vscode·npm·node.js·pnpm
心柠1 天前
webpack
前端·webpack·node.js
FreeBuf_1 天前
vm2 Node.js库曝严重沙箱逃逸漏洞(CVE-2026-22709)可导致任意代码执行
node.js
147API1 天前
改名后的24小时:npm 包抢注如何劫持开源项目供应链
前端·npm·node.js
抵梦1 天前
NPM、CNPM、PNPM:Node.js 依赖工具对比与选择
前端·npm·node.js
哪里不会点哪里.2 天前
NVM:Node.js 版本管理工具
node.js