You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从S3 Bucket向AWS Lambda传输大文件时遇到的问题

AWS Lambda处理S3大文件下载问题

问题描述

  • 基于AWS Lambda实现S3上传事件触发逻辑:从S3获取文件并存入/tmp目录,小文件处理正常,但15MB以上文件失败
  • 已尝试调整Lambda内存、临时存储(ephemeral storage)、超时时间,问题未解决
  • 改用分块下载代码后仍失败,且CloudWatch无相关日志输出(对应15MB文件传输的日志截图无有效内容)

分块下载代码

const fs = require('fs');
const path = require('path');

const s3 = new AWS.S3();

exports.handler = async (event) => {
  const s3Params = {
    Bucket: event.Records[0].s3.bucket.name,
    Key: decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '))
  };
  
  const tempFilePath = path.join('/tmp', s3Params.Key);
  const fileSize = (await s3.headObject(s3Params).promise()).ContentLength;
  const chunkSize = 1024 * 1024; // 1 MB chunks
  
  for (let i = 0; i < fileSize; i += chunkSize) {
    const rangeEnd = Math.min(i + chunkSize - 1, fileSize - 1);
    const range = `bytes=${i}-${rangeEnd}`;
    const chunkParams = {
      ...s3Params,
      Range: range,
    };
    const { Body } = await s3.getObject(chunkParams).promise();
    if (i === 0) {
      fs.writeFileSync(tempFilePath, Body);
    } else {
      fs.appendFileSync(tempFilePath, Body);
    }
  }
  
  console.log(`File downloaded to ${tempFilePath}`);
  console.log("File size is " + fs.statSync(tempFilePath).size );
  
  fs.unlink(tempFilePath, (err) => {
    if (err) 
        throw err;
    console.log('deleted successfully');
});
};

问题排查与解决方案

1. 日志无输出核心原因

Lambda执行可能在触发日志前已崩溃,优先检查:

  • 权限缺失:确认Lambda角色拥有s3:GetObject、s3:HeadObject权限,以及CloudWatch Logs的logs:CreateLogStream、logs:PutLogEvents权限
  • 同步IO阻塞:代码中使用fs.writeFileSync、fs.appendFileSync同步方法,大文件分块时会阻塞事件循环,导致Lambda超时或崩溃,无法输出日志

2. 代码优化方案

改用异步流下载(比分块更高效,避免阻塞):

const fs = require('fs').promises;
const path = require('path');
const { createWriteStream } = require('fs');
const { pipeline } = require('stream/promises');

const s3 = new AWS.S3();

exports.handler = async (event) => {
  const s3Params = {
    Bucket: event.Records[0].s3.bucket.name,
    Key: decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '))
  };
  
  // 避免Key含路径导致/tmp下创建无效目录,仅提取文件名
  const tempFilePath = path.join('/tmp', path.basename(s3Params.Key));
  
  // 通过流直接下载文件,减少内存占用与阻塞
  const s3Stream = s3.getObject(s3Params).createReadStream();
  const fileStream = createWriteStream(tempFilePath);
  
  try {
    await pipeline(s3Stream, fileStream);
    const stats = await fs.stat(tempFilePath);
    console.log(`文件已下载至${tempFilePath},大小:${stats.size}字节`);
    
    await fs.unlink(tempFilePath);
    console.log('临时文件已删除');
  } catch (err) {
    console.error('处理过程出错:', err);
    // 出错时清理临时文件
    try {
      await fs.access(tempFilePath);
      await fs.unlink(tempFilePath);
    } catch (unlinkErr) {
      console.error('删除临时文件失败:', unlinkErr);
    }
    throw err; // 抛出错误标记Lambda执行失败
  }
};

3. 额外配置检查

  • 路径合法性:避免S3 Object Key包含特殊字符或多级路径,改用path.basename提取纯文件名存入/tmp
  • 超时与存储:根据文件大小调整Lambda超时时间(建议设为300秒),确认临时存储配额足够(最大10GB,默认512MB)
  • 内存配置:Lambda内存与网络带宽正相关,建议配置1GB以上内存提升大文件下载速度

内容的提问来源于stack exchange,提问作者Mark Allen Molina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 09:22:47