如何高效将大型JavaScript对象作为JSON文件上传至AWS S3
问题解答
关于JSON.stringify的性能开销
你担心的问题确实存在。150~200MB的JS对象执行JSON.stringify时,会产生接近甚至超过原对象大小的字符串,相当于内存中同时存在两份同量级的数据,总内存占用很容易突破400MB。且JSON.stringify是同步阻塞操作,会占满Lambda的单线程执行资源,如果你的Lambda配置内存低于1GB,大概率会出现执行超时、内存溢出(OOM)的问题。
更高效的实现方案
核心优化思路是避免全量序列化、避免全量数据驻留内存,可以选用以下方案:
方案1:流式序列化+直传S3(最高效)
AWS JS SDK的S3.upload原生支持传入可读流作为Body参数,你可以使用流式JSON序列化库,将JS对象边序列化边上传,全程无需在内存中存储完整的JSON字符串,内存占用可降低到MB级别。
示例代码如下:
const { stringify } = require('@streamparser/json'); const zlib = require('zlib'); const { S3 } = require('aws-sdk'); async function uploadFileOnS3(fileData, s3Detail) { // 1. 创建JSON序列化流 const jsonStream = stringify(fileData); // 2. 可选:添加gzip压缩,大幅降低传输体积和存储成本 const gzipStream = zlib.createGzip(); const uploadStream = jsonStream.pipe(gzipStream); const params = { Bucket: s3Detail.Bucket, Key: s3Detail.Key_response, Body: uploadStream, // 开启压缩的话需要加以下头,后续下载时会自动解压 ContentEncoding: 'gzip', ContentType: 'application/json' }; try { // 配置分块上传参数,按需调整分片大小和并行数 const stored = await S3.upload(params, { partSize: 10 * 1024 * 1024, // 10MB分片 queueSize: 4 // 并行上传4个分片 }).promise(); console.log("file uploaded Sucessfully ", stored); } catch (err) { console.log(err); } console.log("upload exit"); }
方案2:适配上游流式数据源(如果适用)
如果你的fileData本身来自上游流式数据源(比如数据库游标、第三方接口响应流),可以完全避免将整个对象加载到内存,直接在上游数据读取的过程中完成序列化和上传,内存占用可以进一步降到忽略不计。
临时折中方案:提升Lambda配置
如果暂时不想修改序列化逻辑,可以直接把Lambda的内存配置提升到2GB以上。Lambda的CPU性能和内存容量成正比,2GB内存的Lambda对应1vCPU,序列化200MB的JSON通常只需要几百毫秒,内存也足够容纳两份数据,只是成本会略高于流式方案。
内容的提问来源于stack exchange,提问作者Vivek Shukla
相关产品推荐
相关产品推荐

