一、背景
nodejs线上服务日常监控和问题排查,需要能够计算出cpu的使用率。
二、方法
linux查看cpu
1.top
top命令可以查询进程运行的情况。
| PID | USER | %CPU | %MEM | TIME+ | COMMAND |
|---|---|---|---|---|---|
| 1 | user | 7.7 | 0.1 | 408:46.28 | node |
| 2 | user | 3.3 | 0.1 | 418:01.71 | node |
| 3 | user | 2.7 | 0.1 | 434:44.60 | node |
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使用率。
//
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代码解析。