Node-red实现远程服务器性能监测

Node-red实现远程服务器性能监测


  本文主要实现使用Node-RED实现远程服务器性能监测,监测指标包含运行天数、cpu负载、cpu使用率、内存、交换信息等。

一、实现步骤

  1. 安装node-red-contrib-bigssh节点:
npm install -g node-red-contrib-bigssh

Big SSH 是 Node-RED 的输入节点,用于通过 SSH 协议在远程主机上执行命令
核心功能特性‌如下:

    1. 命令配置‌
    • 命令可直接设置为节点的属性值
    • 支持通过有效载荷(payload)动态添加命令参数
    • 命令可定义为 JavaScript 模板字符串,并以 payload 传递变量值
    1. ‌身份验证配置‌
    • 依赖第三方库实现认证模块
    • ‌需注意‌:首次连接需测试交互式应答机制(SSH 默认要求交互确认)
    1. ‌‌命令执行规范‌
    • 必须指定命令的‌完整路径‌(因远程连接后环境变量不生效)
    • 需显式定义 payload 的数据处理逻辑(如参数拼接方式)
  1. 使用top命令获取远程服务器指标:top -b -n 1

top -b -n 1:是Linux 系统监控命令的常用组合,用于以批处理模式获取系统资源的一次性快照
命令返回结构分为五部分

  • 系统运行时间及负载平均值(1/5/15分钟)
  • 任务统计(总进程数、运行/休眠/僵尸进程数)
  • CPU使用详情(用户态/内核态/空闲占比等)
  • 物理内存和交换分区使用量
  • 进程列表(默认按CPU占用排序)

返回数据示例:

top - 16:10:33 up 315 days,  7:24,  2 users,  load average: 0.02, 0.07, 0.12
Tasks: 224 total,   1 running, 223 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.7 us,  2.8 sy,  0.0 ni, 96.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 16265504 total,  3410928 free,  1766692 used, 11087884 buff/cache
KiB Swap:  8257532 total,  8250032 free,     7500 used. 13368544 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
25329 1000      20   0 3670564 263004  93620 S   5.9  1.6   1138:18 beam.smp
28355 root      20   0  162100   2192   1512 R   5.9  0.0   0:00.03 top
    1 root      20   0   54572   6232   3500 S   0.0  0.0 201:38.12 systemd
    2 root      20   0       0      0      0 S   0.0  0.0   0:16.42 kthreadd
    4 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:+
    6 root      20   0       0      0      0 S   0.0  0.0   0:55.03 ksoftirqd/0
    7 root      rt   0       0      0      0 S   0.0  0.0   1:27.17 migration/0
   ...

返回数据解析:

function parseTopOutput(output) {
    let result = {};
    // 提取运行天数
    const uptimeMatch = output.match(/up\s+(\d+)\s+days?,\s+[\d:]+/);
    result.days = uptimeMatch ? parseInt(uptimeMatch[1]) : 0;

    // 提取CPU负载
    const loadMatch = output.match(/load average:\s+([\d.]+),\s+([\d.]+),\s+([\d.]+)/);
    result.cpuLoad = loadMatch ? `${loadMatch[1]}, ${loadMatch[2]}, ${loadMatch[3]}` : null;

    // 提取CPU使用率
    const cpuMatch = output.match(/%Cpu\(s\):\s+([\d.]+)\s+us,\s+([\d.]+)\s+sy,\s+([\d.]+)\s+ni,\s+([\d.]+)\s+id/);
    result.cpuUsage = cpuMatch ? `用户:${cpuMatch[1]}% 系统:${cpuMatch[2]}% 空闲:${cpuMatch[4]}%` : null;

    // 提取内存信息
    const memMatch = output.match(/KiB Mem\s*:\s*(\d+)\s+total,\s*(\d+)\s+free,\s*(\d+)\s+used/);
    result.memory = memMatch ? getMemInfo(memMatch[1], memMatch[3]): null;

    // 提取交换分区信息
    const swapMatch = output.match(/KiB Swap\s*:\s*(\d+)\s+total,\s*(\d+)\s+free,\s*(\d+)\s+used/);
    result.swap = swapMatch ? getMemInfo(swapMatch[1], swapMatch[3]) : null;

    return {
        运行天数: `${result.days}天`,
        CPU负载: result.cpuLoad,
        CPU使用率: result.cpuUsage,
        内存: result.memory,
        交换分区: result.swap
    };
}
/** 设置输出格式:使用百分比% -> 已使用/总量 ,单位由KiB转换为MiB*/
function getMemInfo(total,used){
    const per = ((used / total) * 100).toFixed(1);
    return per +`% -> ${Math.round(used / 1024)}MB/${Math.round(total / 1024)}MB`
}

输出如下:
2

二、源码

2

[
    {
        "id": "940e18a11fe3beb1",
        "type": "bigssh",
        "z": "b6f68decfc53e1bc",
        "name": "",
        "commandLine": "",
        "commandArgs": "",
        "minError": 1,
        "minWarning": 1,
        "noStdin": false,
        "format": "utf8",
        "payloadIsArg": true,
        "myssh": "c46911cf241d534d",
        "x": 650,
        "y": 80,
        "wires": [
            [
                "6104e759a01b23b7"
            ],
            [],
            []
        ]
    },
    {
        "id": "35009a3fa1d0a288",
        "type": "debug",
        "z": "b6f68decfc53e1bc",
        "name": "debug 8",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1140,
        "y": 80,
        "wires": []
    },
    {
        "id": "6104e759a01b23b7",
        "type": "function",
        "z": "b6f68decfc53e1bc",
        "name": "数据转换",
        "func": "msg.flag = false;\nif(msg.payload && msg.payload.startsWith(\"top\")){\n    msg.flag = true;\n    msg.payload = parseTopOutput(msg.payload);\n}\nreturn msg;\nfunction parseTopOutput(output) {\n    let result = {};\n    // 提取运行天数\n    const uptimeMatch = output.match(/up\\s+(\\d+)\\s+days?,\\s+[\\d:]+/);\n    result.days = uptimeMatch ? parseInt(uptimeMatch[1]) : 0;\n\n    // 提取CPU负载\n    const loadMatch = output.match(/load average:\\s+([\\d.]+),\\s+([\\d.]+),\\s+([\\d.]+)/);\n    result.cpuLoad = loadMatch ? `${loadMatch[1]}, ${loadMatch[2]}, ${loadMatch[3]}` : null;\n\n    // 提取CPU使用率\n    const cpuMatch = output.match(/%Cpu\\(s\\):\\s+([\\d.]+)\\s+us,\\s+([\\d.]+)\\s+sy,\\s+([\\d.]+)\\s+ni,\\s+([\\d.]+)\\s+id/);\n    result.cpuUsage = cpuMatch ? `用户:${cpuMatch[1]}% 系统:${cpuMatch[2]}% 空闲:${cpuMatch[4]}%` : null;\n\n    // 提取内存信息\n    const memMatch = output.match(/KiB Mem\\s*:\\s*(\\d+)\\s+total,\\s*(\\d+)\\s+free,\\s*(\\d+)\\s+used/);\n    result.memory = memMatch ? getMemInfo(memMatch[1], memMatch[3]): null;\n\n    // 提取交换分区信息\n    const swapMatch = output.match(/KiB Swap\\s*:\\s*(\\d+)\\s+total,\\s*(\\d+)\\s+free,\\s*(\\d+)\\s+used/);\n    result.swap = swapMatch ? getMemInfo(swapMatch[1], swapMatch[3]) : null;\n\n    return {\n        运行天数: `${result.days}天`,\n        CPU负载: result.cpuLoad,\n        CPU使用率: result.cpuUsage,\n        内存: result.memory,\n        交换分区: result.swap\n    };\n}\n/** 设置输出格式:使用百分比% -> 已使用/总量 ,单位由KiB转换为MiB*/\nfunction getMemInfo(total,used){\n    const per = ((used / total) * 100).toFixed(1);\n    return per +`% -> ${Math.round(used / 1024)}MB/${Math.round(total / 1024)}MB`\n}",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 840,
        "y": 80,
        "wires": [
            [
                "03cbef785d9bc275"
            ]
        ]
    },
    {
        "id": "9abfcfc3a2cafc21",
        "type": "function",
        "z": "b6f68decfc53e1bc",
        "name": "top指令",
        "func": "msg.payload = `top -b -n 1 `;\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 440,
        "y": 80,
        "wires": [
            [
                "940e18a11fe3beb1"
            ]
        ]
    },
    {
        "id": "4b5e31d0def99e0f",
        "type": "inject",
        "z": "b6f68decfc53e1bc",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 290,
        "y": 80,
        "wires": [
            [
                "9abfcfc3a2cafc21"
            ]
        ]
    },
    {
        "id": "03cbef785d9bc275",
        "type": "switch",
        "z": "b6f68decfc53e1bc",
        "name": "",
        "property": "flag",
        "propertyType": "msg",
        "rules": [
            {
                "t": "true"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 990,
        "y": 80,
        "wires": [
            [
                "35009a3fa1d0a288"
            ]
        ]
    },
    {
        "id": "db6efc9b136db406",
        "type": "debug",
        "z": "b6f68decfc53e1bc",
        "name": "debug 9",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 840,
        "y": 40,
        "wires": []
    },
    {
        "id": "c46911cf241d534d",
        "type": "SSH_Credentials",
        "host": "10.50.3.101",
        "port": "22",
        "userlabel": "root@10.50.3.101"
    }
]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值