1. 项目概述:基于Vue与Node.js的机器人健康预警系统
最近在做一个挺有意思的项目——用Vue和Node.js搭建机器人健康预警系统。简单来说,就是给机器人装个"体检医生",实时监控它的运行状态,一旦发现异常就立即报警。这个系统前端用Vue 3+TypeScript,后端用Node.js(NestJS框架),数据库根据数据类型分别选了MySQL和MongoDB。特别适合那些需要7×24小时稳定运行的机器人应用场景,比如工业自动化、服务机器人等领域。
这个系统的核心价值在于:第一,它能实时监控机器人的CPU、内存等关键指标;第二,可以自定义预警规则,比如CPU使用率超过80%持续30秒就触发警报;第三,提供了直观的可视化看板,让运维人员一眼就能掌握机器人集群的健康状况。我自己在开发过程中踩过不少坑,比如初期直接用setInterval做定时检测导致性能问题,后来改用Worker线程才解决。接下来我会详细分享整个系统的设计思路和实现细节。
2. 技术选型与架构设计
2.1 前端技术栈选择
选择Vue 3+TypeScript组合主要基于三个考虑:首先,Vue 3的Composition API让代码组织更清晰,特别是对于需要频繁交互的监控系统;其次,TypeScript的静态类型检查能大大减少运行时错误,这对稳定性要求高的预警系统尤为重要;最后,Element Plus组件库提供了丰富的UI组件,加速了看板开发。
实际开发中,我特别推荐使用Pinia做状态管理而不是Vuex。Pinia的API更简洁,而且对TypeScript支持更好。比如存储预警规则的状态可以这样定义:
typescript复制// stores/rules.ts
import { defineStore } from 'pinia'
export const useRulesStore = defineStore('rules', {
state: () => ({
rules: [] as Rule[],
loading: false
}),
actions: {
async fetchRules() {
this.loading = true
try {
const { data } = await api.get('/rules')
this.rules = data
} finally {
this.loading = false
}
}
}
})
2.2 后端架构设计
后端选用NestJS而不是纯Express,主要看中它的模块化架构和开箱即用的TypeScript支持。NestJS的模块系统让代码组织更清晰,特别适合需要长期维护的项目。系统主要分为以下几个模块:
- 监控模块:负责采集机器人的各项指标
- 预警模块:根据规则判断是否触发预警
- 通知模块:通过邮件/短信发送预警信息
- 数据模块:处理监控数据的存储和查询
对于实时性要求高的预警功能,我使用了Socket.io来实现WebSocket通信。当检测到异常时,后端会立即推送消息到前端:
typescript复制// websocket.gateway.ts
@WebSocketGateway()
export class AlertGateway {
@WebSocketServer()
server: Server
@SubscribeMessage('subscribe')
handleSubscribe(client: Socket) {
// 客户端订阅预警通知
client.join('alerts')
}
sendAlert(alert: Alert) {
// 推送预警到所有订阅的客户端
this.server.to('alerts').emit('alert', alert)
}
}
2.3 数据库选型考量
采用MySQL+MongoDB混合存储的策略是基于数据类型的特点:
-
MySQL存储:
- 系统配置信息
- 用户账户数据
- 预警规则定义
- 选择理由:这些数据具有明确的表结构,需要ACID事务支持
-
MongoDB存储:
- 机器人的实时监控数据
- 历史预警记录
- 系统日志
- 选择理由:这些数据量大且结构灵活,需要高性能写入和灵活查询
特别提醒:如果监控数据量特别大(比如每秒上千条记录),建议对MongoDB做分片处理。我在测试阶段就遇到过单机MongoDB写入瓶颈的问题。
3. 核心功能实现细节
3.1 健康检测模块实现
健康检测是系统最核心的功能,需要平衡检测精度和性能开销。最初我用简单的setInterval实现,但发现当检测逻辑复杂时会阻塞事件循环。最终方案是:
javascript复制// monitor.service.ts
import { Worker } from 'worker_threads'
class MonitorService {
private worker: Worker
startMonitoring(interval = 5000) {
this.worker = new Worker('./monitor.worker.js', {
workerData: { interval }
})
this.worker.on('message', (metrics) => {
this.checkThresholds(metrics)
})
}
private checkThresholds(metrics) {
// 阈值检查逻辑...
}
}
对应的Worker线程代码:
javascript复制// monitor.worker.js
const { parentPort, workerData } = require('worker_threads')
setInterval(() => {
const metrics = {
cpu: process.cpuUsage(),
memory: process.memoryUsage(),
timestamp: Date.now()
}
parentPort.postMessage(metrics)
}, workerData.interval)
重要提示:Worker线程间通信有序列化开销,不适合高频小数据量传输。实测下来5秒间隔是个平衡点。
3.2 动态预警规则引擎
为了让非技术人员也能配置预警规则,我设计了一个基于JSON的规则引擎:
json复制{
"rules": [
{
"metric": "cpu",
"condition": ">",
"threshold": 80,
"duration": 30,
"severity": "warning",
"actions": ["email", "dashboard"]
},
{
"metric": "memory.heapUsed",
"condition": ">",
"threshold": 500,
"unit": "MB",
"severity": "critical",
"actions": ["sms", "restart"]
}
]
}
规则引擎的核心处理逻辑:
typescript复制class RuleEngine {
async evaluate(metrics) {
const rules = await this.loadRules()
for (const rule of rules) {
const value = this.getMetricValue(metrics, rule.metric)
if (this.checkCondition(value, rule)) {
this.triggerActions(rule)
}
}
}
private checkCondition(value, rule) {
switch (rule.condition) {
case '>': return value > rule.threshold
case '<': return value < rule.threshold
case '=': return value === rule.threshold
// 更多条件判断...
}
}
}
3.3 可视化看板设计
看板使用ECharts实现实时数据展示,这里有几个优化技巧:
- 数据采样:对于长时间段的趋势图,不要渲染所有数据点
- 虚拟滚动:预警历史表格实现虚拟滚动应对大数据量
- 动画优化:适当减少动画效果提升性能
一个典型的折线图组件实现:
vue复制<template>
<div ref="chart" style="width: 100%; height: 300px"></div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue'
import * as echarts from 'echarts'
const props = defineProps(['data'])
const chart = ref(null)
onMounted(() => {
const instance = echarts.init(chart.value)
const updateChart = () => {
instance.setOption({
xAxis: { type: 'time' },
yAxis: { type: 'value' },
series: [{
data: props.data,
type: 'line',
smooth: true,
showSymbol: false
}]
})
}
watch(() => props.data, updateChart)
})
</script>
4. 性能优化与异常处理
4.1 关键性能优化措施
-
Redis缓存:对频繁访问的规则数据和静态配置进行缓存
typescript复制// 带缓存的规则获取 async getRules() { const cached = await redis.get('rules') if (cached) return JSON.parse(cached) const rules = await db.getRules() await redis.set('rules', JSON.stringify(rules), 'EX', 60) return rules } -
历史数据分页:监控数据只保留最近3个月的详细数据,更早的数据做聚合存储
-
前端懒加载:看板的不同模块按需加载,减少初始加载时间
4.2 异常恢复机制
-
进程守护:使用PM2的cluster模式,配置自动重启
bash复制pm2 start ecosystem.config.js --env productionjavascript复制// ecosystem.config.js module.exports = { apps: [{ name: 'monitor', script: './dist/main.js', instances: 'max', exec_mode: 'cluster', autorestart: true, max_restarts: 10 }] } -
熔断机制:当错误率超过阈值时自动降级
typescript复制class CircuitBreaker { private failures = 0 private lastFailure = 0 private state: 'closed' | 'open' | 'half-open' = 'closed' async execute(fn) { if (this.state === 'open') { if (Date.now() - this.lastFailure > 30000) { this.state = 'half-open' } else { throw new Error('Service unavailable') } } try { const result = await fn() if (this.state === 'half-open') { this.state = 'closed' this.failures = 0 } return result } catch (err) { this.failures++ this.lastFailure = Date.now() if (this.failures > 5) { this.state = 'open' } throw err } } }
5. 部署与持续集成
5.1 容器化部署方案
Dockerfile配置要点:
dockerfile复制# 使用多阶段构建减小镜像体积
FROM node:18 as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
EXPOSE 3000
CMD ["node", "dist/main.js"]
最佳实践:
- 使用
.dockerignore排除不需要的文件 - 生产环境使用alpine版本镜像减小体积
- 设置合理的资源限制
5.2 CI/CD流程设计
GitHub Actions配置示例:
yaml复制name: CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '18'
- run: npm ci
- run: npm test
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: echo "${{ secrets.DOCKER_TOKEN }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- run: docker build -t your-image .
- run: docker push your-image
- run: ssh deploy@server "docker pull your-image && docker-compose up -d"
6. 开发经验与避坑指南
6.1 常见问题排查
-
内存泄漏:
- 现象:Node进程内存持续增长
- 排查:使用
node --inspect配合Chrome DevTools Memory面板 - 解决:确保事件监听器和定时器及时清理
-
数据库连接耗尽:
- 现象:出现"Too many connections"错误
- 排查:检查连接池配置和连接释放逻辑
- 解决:使用连接池并设置合理大小
-
前端性能问题:
- 现象:看板操作卡顿
- 排查:Chrome Performance面板记录性能
- 解决:优化大数据量渲染,使用虚拟滚动
6.2 开发阶段建议
-
MVP阶段:
- 先实现最基本的监控和预警功能
- 使用控制台输出代替完整通知系统
- 验证核心指标采集的准确性
-
扩展阶段:
- 添加可视化看板
- 完善通知渠道(邮件、短信)
- 实现规则配置界面
-
优化阶段:
- 性能调优
- 异常处理增强
- 安全加固
这个项目从技术选型到最终部署,每个环节都有不少值得注意的细节。比如在规则引擎设计时,最初版本没有考虑单位转换,导致内存阈值配置时有的用MB有的用GB,后来才统一了单位系统。再比如ECharts渲染大量数据时,最初是全量渲染导致页面卡顿,后来实现了数据采样才解决。