web前端 - nodejs如何获取cpu占用率

1,842 阅读2分钟

一、背景

nodejs线上服务日常监控和问题排查,需要能够计算出cpu的使用率。

二、方法

linux查看cpu

1.top

top命令可以查询进程运行的情况。

PIDUSER%CPU%MEMTIME+COMMAND
1user7.70.1408:46.28node
2user3.30.1418:01.71node
3user2.70.1434:44.60node

2.vmstat

vmstat命令可以查看系统整体运行情况。

vmstat 1 //查看系统运行情况,1代表每一秒执行一次

3./proc

文档:www.kernel.org/doc/html/la…

/proc是Linux自带的一个虚拟文件系统,可以通过文件操作的方式与linux内核进行通信。

查看cpu信息
cat /proc/cpuinfo

查看平均负载
cat /proc/loadavg

查看uptime
cat /proc/uptime

查看cpu统计信息
cat /proc/stat

查看pid=2的进程统计信息
cat /proc/2/stat

具体每个文件读取后可以获取哪些字段,可以参考:man7.org/linux/man-p…, 或直接使用man命令查看。

获取进程CPU数据我们通常会访问/proc/${pid}/stat,读取后可以根据文档获取对应列的字段值,下面列举几个常用的重要的进程运行数据。

utime:用户模式下的总时间,单位是clock

Amount of time that this process has been scheduled in user mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK) ).  This includes guest time, guest_time (time spent running a virtual CPU, see below), so that applications that are not aware of
the guest time field do not lose that time from their calculations.

stime:内核模式下的总时间,单位是clock
Amount of time that this process has been scheduled in kernel mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK) ).

cutime:等待子进程用户模式下的总时间

Amount of time that this process's waited-for children have been scheduled in user mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK) ).(See also times(2).)  This includes guest time, cguest_time (time spent running a virtual CPU, see below).

cstime:等待子进程内核模式下的总时间

Amount of time that this process's waited-for children have been scheduled in kernel mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK) ).

rss:进程常驻内存

starttime:进程开始运行的时间,是一个相对于系统启动的相对时间

4.pidusage

pidusage是一个第三方依赖,能够获取进程的性能数据。

const pidusage = require('pidusage')

pidusage(process.pid, function (err, stats) {
  console.log(stats)
  // => {
  //   cpu: 10.0,            // percentage (from 0 to 100*vcore)
  //   memory: 357306368,    // bytes
  //   ppid: 312,            // PPID
  //   pid: 727,             // PID
  //   ctime: 867000,        // ms user + system time
  //   elapsed: 6650000,     // ms since the start of the process
  //   timestamp: 864000000  // ms since epoch
  // }
  cb()
})

这个库支持Linux/MAC/windows平台,其中linux平台的实现是基于3中的/proc文件系统实现:在2个不同的时间点读取/proc/${pid}/stat文件,计算得出这段时间内的cpu使用率。

关键代码:github.com/soyuka/pidu…

// 
open(path, cb) {

}

function cb(err, buffer) {
  if (err) {
    // 错误处理
  }
  
  const stat = { ... };
  
  const childrens = options.childrens ? stat.cutime + stat.cstime : 0
  
  // 内核态时间 - 上次的内核态时间 + 用户态时间 - 上次的用户态时间 + 等待子进程的总时间。
  const total = (stat.stime - (hst.stime || 0) + stat.utime - (hst.utime || 0) + childrens
  
  // time elapsed between calls in seconds
  const seconds = Math.abs(hst.uptime !== undefined ? stat.uptime - hst.uptime : stat.start - stat.uptime)
  
  const cpu = seconds > 0 ? (total / seconds) * 100 : 0;
}

child_process

Node api

1.os.cpu
import os from 'os';

// 获取当前时刻CPU的信息,返回空闲时间和总时间
// 这里简单地把所有CPU的耗时累加了,严谨地计算应该单独计算每个cpu的时间,求出每个cpu的使用率
getCPUInfo = () => {
  return os.cpus().map((info: any) => {
    return {
      idle: info.times.idle,
      total: info.times.user + info.times.nice + info.times.sys + info.times.idle + info.times.irq
    };
  }).reduce((pre, cur) => {
    return {
      idle: pre.idle + cur.idle,
      total: pre.total + cur.total,
    };
  }, { idle: 0, total: 0 });
}

// 通过两个时间点的cpu用时信息,计算出该时间段内cpu用的使用时间和使用率
getCPUUsage() {
  const start = this.getCPUInfo();
  return new Promise((resolve) => {
    setTimeout(() => {
      const end = this.getCPUInfo();
      const idle = end.idle - start.idle;
      const total = end.toal - start.total; 
      const usage = 1 - idle / toal // 0 ~ 1的数字, 如0.5代表50%使用率
      resolve({ idle, total, usage });
    }, 5000);
  });
}
2.child_process

使用child_process开启一个子进程,执行Linux命令,通过stdout获取命令执行的结果,然后使用js代码解析。