为何Node.js启用Cluster模式后Artillery性能测试无提升?
咱们先从你的测试配置、服务代码里拆解几个核心问题,这些都是Cluster没发挥出预期作用的关键原因:
1. 测试压力太小,远未触及单进程处理极限
你的Artillery测试脚本设置的是arrivalRate: 2(每秒仅2个请求),持续10秒总共才20个请求。这种量级的负载,单进程Node.js完全能轻松应对——就像用小推车能拉走的货物,换大卡车也不会更快,因为瓶颈根本不在处理能力上。
要看出Cluster的性能优势,你需要大幅提升测试压力:比如把arrivalRate调到50甚至更高,或者延长测试时长,让单进程的CPU被占满,这时多进程的Cluster才能体现出负载分摊的价值。
2. 服务代码的同步阻塞逻辑,抵消了Cluster的优势
你的路由处理函数里有一个超级耗时的同步循环:
for(let i = 0; i < 10000000000; i++) { }
这是纯CPU密集型的同步操作,会直接阻塞当前进程的事件循环。启用Cluster后,每个请求会被分配到不同子进程,但在请求量小的情况下,每个进程可能只处理1-2个请求,单进程和多进程的耗时差异自然微乎其微。
另外,Node.js的Cluster优势主要体现在IO密集型场景(比如数据库查询、外部API调用)——这类操作会释放事件循环,让进程能同时处理多个请求;而CPU密集型任务本身会占满进程的CPU时间,就算多进程,在请求量不大时,整体性能提升也非常有限。
3. 额外小问题:测试请求命中404,未正确触发业务逻辑
看你的测试结果全是404: 20,说明Artillery的请求路径有误:脚本里target设为"http://localhost:3000/"(末尾带斜杠),加上get的url: "/",实际请求的是http://localhost:3000//(双斜杠),而你的服务只监听了"/"路径,导致请求未命中路由。把target改成"http://localhost:3000"(去掉末尾斜杠)就能解决这个问题,确保请求正确触发你的业务逻辑。
验证Cluster效果的优化建议
- 升级测试压力:修改Artillery脚本,比如设置
arrivalRate: 100、duration: 30,让请求量足够大,压到单进程CPU饱和的状态。 - 替换阻塞逻辑:把那个大循环换成贴近真实场景的异步操作,比如用
setTimeout模拟IO延迟,或者调用数据库/外部API,这样才能体现Cluster在并发处理上的优势。 - 正确启用Cluster:你的服务代码里还没添加Cluster启动逻辑!场景2说启用4个集群,但当前
server.js没有相关代码,你需要补充Cluster的实现:
const cluster = require('cluster'); const numCPUs = require('os').cpus().length; if (cluster.isPrimary) { console.log(`主进程 ${process.pid} 已启动`); // 启动子进程 for (let i = 0; i < numCPUs; i++) { cluster.fork(); } } else { // 子进程的服务代码 var http = require('http'); var express = require('express'); var app = express(); var server = http.createServer(app); app.get('/', function(req, res,next) { // 替换为异步逻辑,模拟真实场景 setTimeout(() => { console.log(`子进程 ${process.pid} 收到请求`); res.send(new Date()); }, 100); }); server.listen(3000, function() { console.log(`子进程 ${process.pid} 已启动,监听端口3000`); }); }
按照上面的建议调整后,再用高压力测试脚本运行,你应该能看到Cluster模式下的RPS(每秒请求数)显著提升,延迟也会更稳定。
内容的提问来源于stack exchange,提问作者Akhil

