MST

星途 面试题库

面试题:如何在 Node.js 中基于 Cluster 模块实现 HTTP 服务负载均衡

假设你需要利用 Node.js 的 Cluster 模块为一个 HTTP 服务搭建负载均衡环境。请详细阐述实现的步骤,包括如何创建子进程、如何分配请求以及如何处理子进程间的通信与错误。
36.4万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

创建子进程

  1. 引入模块:在 Node.js 项目中,首先引入 clusterhttp 模块。
    const cluster = require('cluster');
    const http = require('http');
    const numCPUs = require('os').cpus().length;
    
  2. 主进程逻辑:在主进程中,通过 cluster.fork() 方法创建子进程。一般会根据 CPU 核心数来创建相应数量的子进程。
    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} 已退出`);
            cluster.fork();
        });
    }
    
  3. 子进程逻辑:在子进程(cluster.isWorker)中,创建 HTTP 服务器来处理请求。
    else {
        const server = http.createServer((req, res) => {
            res.writeHead(200);
            res.end('你好,世界!');
        });
        server.listen(3000, () => {
            console.log(`工作进程 ${process.pid} 已启动,监听端口 3000`);
        });
    }
    

分配请求

  1. 负载均衡策略:Node.js 的 cluster 模块内部使用了内置的负载均衡策略,基于 Round - Robin 算法。主进程接收所有的新连接,然后将这些连接循环分配给各个工作进程。
  2. 无需额外代码:对于基本的 HTTP 请求分配,开发者无需额外编写负载均衡分配代码,cluster 模块会自动完成请求在子进程间的均衡分配。

处理子进程间的通信

  1. 发送消息:工作进程和主进程之间可以通过 worker.send(message)process.send(message) 方法来发送消息。例如,工作进程可以向主进程发送其当前的负载情况。
    // 工作进程发送消息
    setInterval(() => {
        process.send({ type: 'load', value: getLoad() });
    }, 1000);
    
  2. 接收消息:通过 cluster.on('message', (worker, message) (主进程)和 process.on('message', (message) (工作进程)来接收消息。例如主进程接收工作进程发送的负载信息。
    // 主进程接收消息
    cluster.on('message', (worker, message) => {
        if (message.type === 'load') {
            console.log(`工作进程 ${worker.process.pid} 的负载: ${message.value}`);
        }
    });
    

处理子进程间的错误

  1. 工作进程错误处理:在工作进程中,可以监听 uncaughtException 事件来处理未捕获的异常。当捕获到异常时,可以向主进程发送错误信息,然后安全地关闭自身。
    process.on('uncaughtException', (err) => {
        console.error('工作进程中发生未捕获异常:', err);
        process.send({ type: 'error', error: err.message });
        process.exit(1);
    });
    
  2. 主进程错误处理:主进程通过监听 clusterexit 事件,当工作进程因为错误退出时,可以选择重新启动该工作进程。
    cluster.on('exit', (worker, code, signal) => {
        console.log(`工作进程 ${worker.process.pid} 已退出,原因: ${code || signal}`);
        cluster.fork();
    });