面试题答案
一键面试创建工作进程
- 引入
cluster
模块: 在 Node.js 应用程序中,首先需要引入cluster
模块。
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
- 主进程创建工作进程:
在主进程中,使用
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();
});
} else {
// 工作进程逻辑
}
主进程和工作进程间分配请求
- 主进程监听端口:
主进程监听指定的端口,然后将接收到的请求分发给工作进程。在 Node.js 中,主进程可以使用
cluster.isMaster
标识来处理这部分逻辑。
if (cluster.isMaster) {
const server = http.createServer((req, res) => {
// 这里主进程不处理请求,只是负责分发
});
server.listen(3000, () => {
console.log('服务器已启动,监听端口 3000');
});
}
- 工作进程处理请求:
工作进程通过
cluster.isWorker
标识来识别自身,并处理接收到的请求。工作进程可以像普通的 Node.js HTTP 服务器一样处理请求。
if (cluster.isWorker) {
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('你好,这是工作进程 ' + process.pid + ' 的响应\n');
});
server.listen();
}
Node.js 的 cluster
模块会自动将请求负载均衡到各个工作进程上,默认使用的是循环调度(Round - Robin)算法。
使用过程中可能遇到的问题及解决方案
- 共享资源问题:
- 问题:工作进程之间是独立的,它们不能直接共享内存等资源。如果需要共享某些数据(如数据库连接池),可能会导致资源重复创建或者数据不一致的问题。
- 解决方案:可以使用外部存储(如 Redis)来共享数据,工作进程通过操作外部存储来实现数据的共享。另外,对于一些资源(如数据库连接池),可以在主进程中创建,然后通过进程间通信(IPC)将连接传递给工作进程。
- 进程间通信问题:
- 问题:在主进程和工作进程之间传递复杂数据结构时,可能会遇到序列化和反序列化的问题,并且不正确的通信可能导致数据丢失或进程崩溃。
- 解决方案:使用
worker.send()
和process.on('message', callback)
进行进程间通信时,确保传递的数据是可序列化的(如 JSON 格式)。同时,在接收端进行必要的数据验证,以防止异常数据导致进程崩溃。
- 错误处理问题:
- 问题:工作进程中的未捕获异常可能导致整个工作进程崩溃,影响服务器的稳定性。
- 解决方案:在工作进程中,使用
process.on('uncaughtException', callback)
捕获未处理的异常,进行适当的错误处理,如记录日志、重启工作进程等。在主进程中,通过监听cluster.on('exit', callback)
事件,当工作进程因为异常退出时,可以及时重启该工作进程。