前言
在 Node.js 开发中,处理 CPU 密集型任务和提升应用性能是常见需求。
今天我们来深入理解 Node.js 提供的两种并发处理方案:Cluster 模块和 Worker Threads 模块。
☺️ 这边要求阅读本文的新手小伙伴要有一个印象:【Cluster】 与【进程】相关,【Worker Threads】 与【线程】相关
小贴士 📚:✨Cluster 的中文意思是集群 ✨Worker Threads 的中文意思是工作线程
官方定义解析
Node.js 官方文档指出:
"Node.js 进程的集群可用于运行多个 Node.js 实例,这些实例可以在其应用程序线程之间分配工作负载。当不需要进程隔离时,请改用 worker_threads 模块,它允许在单个 Node.js 实例中运行多个应用程序线程。"
核心概念解释
进程(Process)
- 拥有【独立内存空间】的程序实例
- 相当于一个独立的应用程序
- 进程间相互隔离,一个崩溃不会影响其他进程
线程(Thread)
- 进程内的执行单元
- 共享进程的内存空间
- 线程间可以更高效地通信
两种方案的对比
Cluster 模块(多进程)
javascript
const cluster = require('cluster')
const os = require('os')
if (cluster.isPrimary) {
// 主进程:创建工作进程
for (let i = 0; i < os.cpus().length; i++) {
cluster.fork()
}
} else {
// 工作进程:启动服务器
require('./server.js')
}
适用场景:
- HTTP 服务器负载均衡
- 需要高隔离性的任务
- 利用多核 CPU 处理并发请求
特点:
- ✅ 进程隔离,稳定性高
- ✅ 充分利用多核 CPU
- ❌ 内存开销较大
- ❌ 进程间通信成本较高
Worker Threads 模块(多线程)
javascript
const {Worker} = require('worker_threads')
function runWorker(data) {
return new Promise((resolve, reject) => {
const worker = new Worker(
`
const { parentPort } = require('worker_threads');
parentPort.on('message', (data) => {
// 执行计算密集型任务
const result = heavyCalculation(data);
parentPort.postMessage(result);
});
`,
{eval: true}
)
worker.on('message', resolve)
worker.on('error', reject)
worker.postMessage(data)
})
}
适用场景:
- CPU 密集型计算任务
- 图像/视频处理
- 大数据分析
- 加密解密操作
特点:
- ✅ 内存共享,开销较小
- ✅ 线程间通信高效
- ❌ 隔离性较差,一个线程崩溃可能影响整个进程
- ❌ 需要处理线程同步问题
选择指南
什么时候用 Cluster?
- 构建 Web 服务器,需要处理大量并发连接。其实可以联想到 pm2 的多进程模式 ------ 经过了解,得知 PM2 的集群模式(pm2 start app.js -i 4)在底层正是使用了 Node.js 的 Cluster 模块 来实现的。
- 任务需要高度的稳定性和隔离性
- 希望充分利用多核 CPU 性能
什么时候用 Worker Threads?
- 需要执行复杂的数学计算或数据处理
- 任务需要共享大量数据
- 希望减少内存开销
- 在单个进程中需要并行处理多个任务
实际应用示例
场景:图像处理服务
javascript
// 使用 Worker Threads 处理图像
const {Worker} = require('worker_threads')
class ImageProcessor {
async processImages(images) {
const workers = images.map(image => this.createWorker('./image-worker.js', image))
const results = await Promise.all(workers)
return results
}
createWorker(workerPath, data) {
return new Promise((resolve, reject) => {
const worker = new Worker(workerPath, {workerData: data})
worker.on('message', resolve)
worker.on('error', reject)
})
}
}
场景:高并发 Web 服务
javascript
// 使用 Cluster 创建 Web 服务器集群
const cluster = require('cluster')
const http = require('http')
const numCPUs = require('os').cpus().length
if (cluster.isPrimary) {
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} 已启动`)
}
性能考量
- 内存使用:Worker Threads 通常比 Cluster 更节省内存
- 启动速度:线程启动比进程启动更快
- 通信成本:线程间通信比进程间通信更高效
- 稳定性:Cluster 提供更好的故障隔离
总结
这边简单做个总结 🍃
- Cluster 适合需要高隔离性和稳定性的 I/O 密集型任务
- Worker Threads 适合需要高效内存使用的 CPU 密集型任务