Promise并发大量请求引发HTTP连接超限(EMFILE)问题求助
解决大量并发请求导致的EMFILE套接字耗尽问题
问题原因
你遇到的connect EMFILE错误,本质是操作系统同时打开的文件描述符(套接字属于文件描述符)数量超过了系统限制。AWS EC2实例默认的文件描述符上限通常在1024左右,一次性发起10000个请求必然会触发这个限制。
解决方案
1. 给Axios配置连接池限制并发连接
直接修改你的Axios实例配置,通过httpsAgent的maxSockets参数限制同时打开的连接数,Axios会自动排队处理超出的请求,避免瞬间占用过多套接字:
import axios from 'axios'; import https from 'https'; const axiosInstance = axios.create({ httpsAgent: new https.Agent({ rejectUnauthorized: false, maxSockets: 50 // 限制同时最多50个并发连接,可根据实际场景调整 }) }); static getCar = async(carId: number) => { try { const response = await axiosInstance.get(`${baseUrl}/v1/car/${carId}.json`); return response.data; } catch (err) { console.error(`获取车辆${carId}数据失败:`, err); return null; } }
2. 分批处理请求
如果需要更精细地控制请求节奏,或者外部API有请求频率限制,可以将10000个请求分成多批,每批只处理固定数量的请求,完成一批后再启动下一批:
// 自定义分批处理函数 async function processInBatches(items, batchSize, handler) { const results = []; const totalBatches = Math.ceil(items.length / batchSize); for (let batchIndex = 0; batchIndex < totalBatches; batchIndex++) { const start = batchIndex * batchSize; const end = start + batchSize; const batch = items.slice(start, end); console.log(`处理第${batchIndex + 1}/${totalBatches}批,共${batch.length}个请求`); const batchResults = await Promise.allSettled(batch.map(item => handler(Number(item.carId)))); results.push(...batchResults); } return results; } // 替换原来的批量请求逻辑 console.log('开始分批处理请求'); const result = await processInBatches(data, 50, getCarData); // 每批50个请求,可按需调整
3. 优化你的getCarData函数
原函数存在Promise嵌套的反模式,简化后更易维护且避免潜在问题:
export const getCarData = async (carId: number) => { const car = await API.getCar(carId); if (!car) { throw new Error('Could not find car'); } return car; }
4. 兜底方案:调整系统文件描述符限制(AWS环境)
如果前两种方案仍无法满足需求,可以临时或持久化提高EC2实例的文件描述符上限:
- 临时生效:登录实例后执行命令
ulimit -n 65535,重启后失效 - 持久化生效:编辑
/etc/security/limits.conf文件,添加以下内容,然后重启实例或重新登录:* soft nofile 65535 * hard nofile 65535
建议
优先采用连接池配置+分批处理的组合方案,既能有效控制并发连接数避免EMFILE错误,也能避免对外部API造成过大压力,同时保证请求处理的效率。
内容的提问来源于stack exchange,提问作者asdasf
相关产品推荐
相关产品推荐

