You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js使用loadtest压测Express服务时出现Error: read ENOTCONN问题

问题分析与解决

错误根源

你的Express服务器里的longComputation()是同步CPU密集型任务,Node.js基于单线程事件循环模型运行,一旦这个函数执行,会完全阻塞事件循环,无法处理任何网络IO(包括新连接建立、已连接socket的读写操作)。当你用loadtest -n 10 -c 10发起10个并发请求时,所有请求会排队等待第一个请求的计算完成,期间客户端(loadtest)的连接长时间得不到响应,被底层网络层判定为无效连接,进而抛出ENOTCONN(尝试对未连接的socket执行读操作)错误。

解决方案:将CPU密集型任务异步化

要解决这个问题,必须把同步阻塞的计算任务移出主线程,避免卡住事件循环。推荐使用Node.js原生的worker_threads模块,把计算任务放到独立的工作线程中执行。

修改后的代码示例

  1. 先创建独立的工作线程文件compute.worker.js:
// compute.worker.js
const { parentPort } = require('worker_threads');

parentPort.on('message', () => {
    let sum = 0;
    for(let i=0; i < 1e9; i++){
        sum += i; 
    }
    parentPort.postMessage(sum);
});
  1. 修改主Express服务器代码:
const express = require('express');
const { Worker } = require('worker_threads');
const app = express();

app.get('/one', (req, res) => {
    console.log('received one request');
    // 创建工作线程处理计算任务
    const worker = new Worker('./compute.worker.js');
    worker.postMessage('start');
    // 接收工作线程返回的计算结果
    worker.on('message', (sum) => {
        res.send({sum: sum});
        worker.terminate(); // 计算完成后销毁线程释放资源
    });
    // 捕获工作线程异常
    worker.on('error', (err) => {
        res.status(500).send({error: err.message});
        worker.terminate();
    });
});

app.listen(5632, () => {
    console.log(`Server listening on 5632...`)
});

额外优化建议

  • 可以搭建工作线程池,避免每次请求都创建新线程,减少线程创建销毁的资源开销。
  • 如果计算任务可拆分,也可以用setImmediate分批次执行循环,每次只处理一部分计算后让出事件循环处理IO,但这种方式总执行时间会更长,仅适合对耗时要求不高的场景。

测试验证

修改完成后,再次执行压测命令:

loadtest -n 10 -c 10 http://localhost:5632/one

此时服务器可以正常处理并发请求,不会再出现ENOTCONN错误。

内容的提问来源于stack exchange,提问作者Pooja Seethur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 00:53:10