Node.js负载测试出现ECONNREFUSED/ETIMEDOUT问题求助
负载测试中axios请求频繁出现ECONNREFUSED/ETIMEDOUT的代码优化方案
开发环境负载测试场景:客户端向Node.js服务器并行发送多API请求,处理10万条记录(每条需发起20-25次API调用),初期运行正常,成功处理7.5-8万条后频繁出现
ECONNREFUSED/ETIMEDOUT错误。已使用单例axios实例,实现退避重试机制但效果不佳,CPU使用率未达上限。当前axios配置如下:
const Agent = require('agentkeepalive'); const HttpsAgent = require('agentkeepalive').HttpsAgent; import axios from 'axios'; const Cacheable = require('cacheable-lookup'); let cacheable = new Cacheable.default({ maxTtl: 300 }); let instance; const keepAliveAgent = new Agent({ maxSockets: 1500, maxFreeSockets: 256, timeout: 5 * 60000, freeSocketTimeout: 5000, keepAlive: true, keepAliveMsecs: 60000, }); // HTTPS agent const httpsKeepAliveAgent = new HttpsAgent({ maxSockets: 1500, maxFreeSockets: 256, timeout: 5 * 60000, freeSocketTimeout: 5000, keepAlive: true, keepAliveMsecs: 60000, }); // Attach cacheable-lookup to the agents cacheable.install(keepAliveAgent); cacheable.install(httpsKeepAliveAgent); const axiosInstanceGenerator = () => { if (!instance) { instance = axios.create({ timeout: 30 * 60000, httpAgent: keepAliveAgent, httpsAgent: httpsKeepAliveAgent, }); } return instance; }; export const axiosInstance = axiosInstanceGenerator();
优化方案
一、调整连接池参数,避免目标服务器过载
当前maxSockets设置过高(1500),可能超出目标服务器的连接承载上限;maxFreeSockets偏低导致闲置连接快速回收,新建连接开销累积。调整参数如下:
const keepAliveAgent = new Agent({ maxSockets: 500, // 降低并发连接数,匹配目标服务器能力 maxFreeSockets: 1000, // 增加空闲连接保留数,减少新建连接频率 timeout: 5 * 60000, freeSocketTimeout: 30000, // 延长空闲连接超时,避免频繁销毁重建 keepAlive: true, keepAliveMsecs: 60000, }); const httpsKeepAliveAgent = new HttpsAgent({ maxSockets: 500, maxFreeSockets: 1000, timeout: 5 * 60000, freeSocketTimeout: 30000, keepAlive: true, keepAliveMsecs: 60000, });
二、优化DNS缓存注入逻辑
cacheable-lookup绑定到agent的方式存在兼容性风险,改为直接注入axios的lookup配置:
// 简化Cacheable实例化方式 const cacheable = new Cacheable({ maxTtl: 300 }); const axiosInstanceGenerator = () => { if (!instance) { instance = axios.create({ timeout: 5 * 60000, // 与agent超时对齐,避免逻辑冲突 httpAgent: keepAliveAgent, httpsAgent: httpsKeepAliveAgent, lookup: cacheable.lookup.bind(cacheable) // 直接注入DNS缓存 }); } return instance; };
三、实现智能重试+流量限流
现有重试机制未区分错误类型,且无流量控制,导致无效重试加剧连接压力。结合axios-retry和p-limit优化:
- 安装依赖:
npm install axios-retry p-limit
- 修改代码:
import axiosRetry from 'axios-retry'; import pLimit from 'p-limit'; // 限制并发请求数,避免瞬间打满连接池 const requestLimit = pLimit(400); const axiosInstanceGenerator = () => { if (!instance) { instance = axios.create({ timeout: 5 * 60000, httpAgent: keepAliveAgent, httpsAgent: httpsKeepAliveAgent, lookup: cacheable.lookup.bind(cacheable) }); // 配置差异化重试规则 axiosRetry(instance, { retries: 3, retryDelay: (retryCount) => Math.pow(2, retryCount) * 1000, // 指数退避:1s→2s→4s retryCondition: (error) => { // 仅对连接类错误重试,跳过业务错误 return axiosRetry.isNetworkError(error) || error.code === 'ECONNREFUSED' || error.code === 'ETIMEDOUT'; }, shouldResetTimeout: true // 重试时重置超时时间 }); } return instance; }; // 用限流包装请求 export const limitedAxiosRequest = (config) => { return requestLimit(() => axiosInstance.request(config)); };
四、添加连接池状态监控
定时打印连接池状态,排查是否存在连接泄漏:
// 每10秒打印一次连接池状态 setInterval(() => { console.log('HTTP Agent 状态:', { 总连接数: keepAliveAgent.totalSockets, 空闲连接数: keepAliveAgent.freeSockets, 活跃连接数: Object.keys(keepAliveAgent.sockets).reduce((sum, key) => sum + keepAliveAgent.sockets[key].length, 0) }); console.log('HTTPS Agent 状态:', { 总连接数: httpsKeepAliveAgent.totalSockets, 空闲连接数: httpsKeepAliveAgent.freeSockets, 活跃连接数: Object.keys(httpsKeepAliveAgent.sockets).reduce((sum, key) => sum + httpsKeepAliveAgent.sockets[key].length, 0) }); }, 10000);
若发现总连接数持续增长、空闲连接未回收,需检查请求是否未正确捕获错误(未释放连接)。
内容的提问来源于stack exchange,提问作者WizRd AM
相关产品推荐
相关产品推荐

