提问人:hg.park 提问时间:10/11/2023 最后编辑:hg.park 更新时间:10/12/2023 访问量:51
在 promise.all() 中下载 s3 客户端时网络连接丢失
Lost network connection while downloading s3 client within promise.all()
问:
我正在使用一个基于 nodejs 的服务器,该服务器从 s3 下载 1000 个 pdf 文件,每个 9MB 文件,将它们压缩成一个 zip 文件,然后返回 URL。
但是,从 S3 下载时出现问题。 当我开始在 S3 上下载时,下载了大约 100 个下载,然后无法连接 Internet。 看起来它与大小无关,因为在尝试使用 5GB 文件的 1 个文件时它成功了。
这会导致 mysql 连接丢失>事务失败、连接丢失[ERROR] Error: BEGIN; - Can't add new command when connection is in closed state
我怀疑不应该将繁重的网络操作放在 promise.all() 中,但我不知道确切的原因。帮助!
await Promise.all(
Ids.map((id) => {
const readablePayloads: Array<{ filename: string; bugffer: Readable; }> = [];
// get key, bucket by id
const buffer = await S3Helper.getReadable({bucket, key} {accessKeyId, secretAccessKey});
readablePayloads.push({ filename, buffer });
})
)
static async getReadable(opts: { bucket: string; key: string }, awsOpts: AwsOptions): Promise<Readable> {
return (await createS3Client(awsOpts).send(new AWS.GetObjectCommand({ Bucket: opts.bucket, Key: opts.key }))).Body as Readable;
}
可以肯定的是,此代码的工作量少于 100 个连接
答:
0赞
Edgar P-Yan
10/12/2023
#1
我看到这个问题的几个可能原因:
文件描述符限制。
任何打开的连接都使用文件描述符。Linux 对每个进程的文件描述符的默认限制为 1024。因此,除了分叉 node.js 进程或增加限制之外,您对此无能为力。除非你有很好的理由,否则不建议使用后者。另一种方法是限制连接数量,我将在下面介绍。内存堆限制。
这种可能性较小,但仍然:每个打开的连接都会使用一定数量的内存。此外,根据您编写代码和处理可读流的方式,可读流中可能会有过多的缓冲,甚至内存泄漏。
限制连接数
以较小的组下载文件,而不是一次下载所有文件。它可能看起来像这样:
// _.chunk comes from the `lodash` library.
// Now `chunksOfIds` is an array of arrays, each of which contains up to 100 ids.
// i.e [[1,2,...,100],[101,102,...,200],...,[1001,1002,...,1100]]
const chunksOfIds = _.chunk(Ids, 100)
for (const chunk of chunksOfIds) {
const readablePayloadsOfThisChunk: Array<{ filename: string; bugffer: Readable; }> = [];
chunk.map((id) => {
// get key, bucket by id
const buffer = await S3Helper.getReadable({bucket, key} {accessKeyId, secretAccessKey});
readablePayloadsOfThisChunk.push({ filename, buffer });
})
// Note: you have to process your `readablePayloads` here, in the loop,
// so that you will finish your computations before the processing of the next chunk will start
await processReadablePayloads(readablePayloadsOfThisChunk)
}
评论
0赞
hg.park
10/12/2023
非常感谢您的回复。我以类似的方式解决了这个问题。不同之处在于我将 Promise.all() 添加到 map() 中。此外,我发现的原因之一是使用 Readable 类型。尽管我将其限制为像您的解决方案这样的块,但我认为 Readable 类型在 s3Client 端保持连接,直到流完成。因此,目前,我们使用的是 Buffer 类型,但由于速度问题,可能会有进一步的更新。
评论