基于Node.js的S3批量下载时网络中断及MySQL连接丢失问题求助
问题原因与解决方案
核心原因
你使用Promise.all一次性发起1000个S3下载请求,会瞬间耗尽Node.js的TCP连接池/系统文件描述符上限。Node.js的HTTP模块默认对每个域名的并发套接字数有限制(通常为10),AWS SDK虽有自己的连接池配置,但上千个并发请求远超合理阈值,导致后续请求无法建立网络连接。
这种网络资源耗尽会影响整个进程的网络操作,包括MySQL连接——长时间无操作或无法发送心跳包,会被MySQL服务器主动断开连接,最终触发事务失败的报错。
而测试5个1GB文件时,并发数仅为5,远低于连接池上限,因此能正常完成下载。
解决方案
1. 限制并发请求数
放弃Promise.all一次性发起所有请求,改用带并发限制的异步遍历,将并发数控制在20-50之间(可根据服务器配置调整)。推荐使用p-limit库实现,也可自行编写简单的并发控制逻辑:
import pLimit from 'p-limit'; // 设置最大并发数为30 const limit = pLimit(30); const readablePayloads: Array<{ filename: string; buffer: Readable; }> = []; // 用limit包装每个下载任务 await Promise.all(Ids.map(id => limit(async () => { // 根据id获取bucket和key const buffer = await S3Helper.getReadable({bucket, key}, {accessKeyId, secretAccessKey}); readablePayloads.push({ filename, buffer }); })));
2. 优化AWS SDK连接池配置
调整S3客户端的HTTP连接池参数,避免连接耗尽:
import { S3Client } from '@aws-sdk/client-s3'; import { NodeHttpHandler } from '@aws-sdk/node-http-handler'; import https from 'https'; function createS3Client(awsOpts) { return new S3Client({ ...awsOpts, requestHandler: new NodeHttpHandler({ httpsAgent: new https.Agent({ maxSockets: 50 // 调整为符合服务器资源的数值 }) }) }); }
3. 修复代码中的错误
原代码存在两处明显问题:
- 变量名拼写错误:
bugffer应改为buffer readablePayloads声明在map回调内部,每次循环都会重新创建,最终无法收集到任何数据,需将其移至回调外部
4. 防止MySQL连接被断开
由于下载过程耗时较长,MySQL连接可能因长时间闲置被服务器主动断开。可采取以下措施:
- 使用MySQL连接池时,设置合理的
connectionLimit和idleTimeout参数 - 在下载过程中定期向MySQL发送心跳请求(如
SELECT 1;),保持连接活跃
内容的提问来源于stack exchange,提问作者hg.park
相关产品推荐
相关产品推荐

