如何在AWS Lambda(Node.js)中读取S3内80MB以上大TXT文件并提取URL
解决AWS Lambda读取S3大文件内存溢出问题
问题原因
当前代码会把S3文件的所有数据块缓存到数组中,最后拼接成完整字符串。80MB以上的文件会直接占满Lambda的内存(默认128MB),导致函数崩溃。Lambda内存资源有限,加载大文件到内存既不高效也没必要。
解决方案
采用流式逐行处理,无需加载整个文件到内存,每读取一行就解析其中的URL,处理完即释放对应内存,大幅降低内存占用。
核心优化点
- 用Node.js的
readline模块将S3数据流转换为逐行可读流 - 逐行扫描文本,通过正则匹配提取URL
- 实时收集结果,避免内存堆积
修改后的代码
console.log("Loading function"); import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"; import { createInterface } from "readline"; const s3 = new S3Client({ region: "us-west-2" }); // 可根据实际需求调整URL匹配正则 const URL_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g; export const handler = async (event, context) => { console.log("Received event:"); const bucket = event.Records[0].s3.bucket.name; const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")); const extractedUrls = new Set(); // 自动去重 try { const response = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key })); // 创建逐行读取接口 const rl = createInterface({ input: response.Body, crlfDelay: Infinity // 兼容所有换行格式 }); // 监听每行数据,提取URL rl.on("line", (line) => { const matches = line.match(URL_REGEX); if (matches) { matches.forEach(url => extractedUrls.add(url)); } }); // 等待流处理完成 await new Promise((resolve, reject) => { rl.on("close", resolve); rl.on("error", reject); }); console.log(`提取到${extractedUrls.size}个唯一URL`); // 可根据需求将结果写入S3或其他服务,直接返回注意大小限制(Lambda返回上限6MB) return Array.from(extractedUrls); } catch (err) { console.log(err); const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`; console.log(message); throw new Error(message); } };
额外建议
- 调整Lambda内存:若处理超大型文件,可适当调高内存配置(同时CPU性能会提升,处理速度更快)
- 结果存储:若提取的URL数量过多,建议将结果写入另一个S3文件,避免触发Lambda返回大小限制
- 正则优化:根据实际URL格式调整正则表达式,提升匹配准确性
内容的提问来源于stack exchange,提问作者Midas Dev
相关产品推荐
相关产品推荐

