MST
星途 面试题库

面试题:JavaScript 如何监控 Node 进程的 CPU 使用率并进行优化

基于《JavaScript监控Node进程运行状态》,描述如何通过JavaScript实时监控Node进程的CPU使用率。当发现CPU使用率过高时,你会从哪些方面去优化Node进程,给出优化思路和相关代码示例。
19.8万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

实时监控Node进程CPU使用率

  1. 使用os模块和process对象
    • 在Node.js中,可以通过os模块获取系统级别的信息,结合process对象来计算CPU使用率。
    • 示例代码如下:
const os = require('os');
const process = require('process');

// 记录开始时间和CPU使用情况
const startUsage = process.cpuUsage();
const startTime = Date.now();

setInterval(() => {
    const endUsage = process.cpuUsage(startUsage);
    const endTime = Date.now();
    const cpuUsagePercent = (endUsage.user + endUsage.system) / ((endTime - startTime) / 1000) / os.cpus().length * 100;
    console.log(`CPU使用率: ${cpuUsagePercent.toFixed(2)}%`);
}, 1000);
  1. 使用node - native - performance - hooks模块(Node.js v8.5.0+)
    • 该模块提供了更精确的性能测量能力。
    • 示例代码如下:
const { performance } = require('perf_hooks');
const os = require('os');
const process = require('process');

const startUsage = process.cpuUsage();
const startTime = performance.now();

setInterval(() => {
    const endUsage = process.cpuUsage(startUsage);
    const endTime = performance.now();
    const cpuUsagePercent = (endUsage.user + endUsage.system) / ((endTime - startTime) / 1000) / os.cpus().length * 100;
    console.log(`CPU使用率: ${cpuUsagePercent.toFixed(2)}%`);
}, 1000);

优化思路及代码示例

  1. 优化算法
    • 思路:检查业务逻辑中的算法,是否存在复杂度较高的算法,例如O(n²)的算法可以优化为O(n log n)甚至O(n)的算法。
    • 示例:假设原代码使用冒泡排序,这是一个O(n²)的算法。可以优化为使用快速排序(平均时间复杂度O(n log n))。
// 原冒泡排序
function bubbleSort(arr) {
    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                let temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    return arr;
}

// 优化为快速排序
function quickSort(arr) {
    if (arr.length <= 1) {
        return arr;
    }
    const pivot = arr[Math.floor(arr.length / 2)];
    const left = [];
    const right = [];
    const equal = [];
    for (let num of arr) {
        if (num < pivot) {
            left.push(num);
        } else if (num > pivot) {
            right.push(num);
        } else {
            equal.push(num);
        }
    }
    return [...quickSort(left), ...equal, ...quickSort(right)];
}
  1. 内存管理
    • 思路:避免内存泄漏,确保及时释放不再使用的变量和对象。例如,清除事件监听器、关闭数据库连接等。
    • 示例:假设使用http模块创建服务器,并且为request事件添加了监听器,在服务器关闭时需要移除监听器。
const http = require('http');

const server = http.createServer((req, res) => {
    res.end('Hello World');
});

function handleRequest(req, res) {
    res.end('Hello World');
}
server.on('request', handleRequest);

server.listen(3000, () => {
    console.log('Server running on port 3000');
});

// 关闭服务器时移除监听器
server.on('close', () => {
    server.removeListener('request', handleRequest);
});
  1. 异步处理
    • 思路:将阻塞的同步操作改为异步操作,充分利用Node.js的事件循环机制。例如,使用fs.readFile(异步)代替fs.readFileSync(同步)。
    • 示例
const fs = require('fs');

// 同步读取文件
// const data = fs.readFileSync('example.txt', 'utf8');
// console.log(data);

// 异步读取文件
fs.readFile('example.txt', 'utf8', (err, data) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log(data);
});
  1. 模块优化
    • 思路:检查引入的模块是否存在不必要的功能,或者是否有更轻量级的替代模块。例如,如果只是需要简单的日志记录,console.log可能就足够,而不需要引入像winston这样功能丰富但相对较重的日志模块。
    • 示例:假设原代码使用winston进行简单日志记录。
// 原代码使用winston
// const winston = require('winston');
// const logger = winston.createLogger({
//     level: 'info',
//     format: winston.format.json(),
//     transports: [
//         new winston.transport.Console()
//     ]
// });
// logger.info('This is a log');

// 优化为使用console.log
console.log('This is a log');
  1. 集群化
    • 思路:对于多核CPU的服务器,可以使用Node.js的集群模块(cluster)将负载分配到多个工作进程,充分利用多核资源。
    • 示例
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    console.log(`主进程 ${process.pid} 正在运行`);

    for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    cluster.on('exit', (worker, code, signal) => {
        console.log(`工作进程 ${worker.process.pid} 已退出`);
    });
} else {
    http.createServer((req, res) => {
        res.writeHead(200);
        res.end('你好,世界\n');
    }).listen(8000, () => {
        console.log(`工作进程 ${process.pid} 已启动`);
    });
}