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

如何用Python Lambda流式压缩S3文件并上传至另一S3存储桶

基于流式处理的S3到S3实时压缩Lambda实现

嘿,我完全懂你遇到的问题——Lambda那500MB的/tmp存储确实不够用,而且磁盘IO不仅拖慢性能,还可能在处理大文件时触发限制。流式处理绝对是最优解,全程在内存中读写数据,完全不用落地到磁盘。下面是一个完整的Python端到端实现,涵盖所有必要细节:

核心思路

我们会用boto3的流式API直接读取源S3对象的内容,通过Python的gzip库实时压缩数据流,最后再通过流式API上传到目标S3桶。整个过程没有任何磁盘写入操作,完全依赖内存流处理。

完整代码实现

import boto3
import gzip
import io
import os

# 从环境变量获取目标桶名(推荐用环境变量,避免硬编码)
TARGET_BUCKET = os.environ.get('TARGET_S3_BUCKET')

s3_client = boto3.client('s3')

def lambda_handler(event, context):
    # 解析S3触发事件
    for record in event['Records']:
        source_bucket = record['s3']['bucket']['name']
        source_key = record['s3']['object']['key']
        
        # 生成目标键(这里给原文件名加上.gz后缀,你可以自定义规则)
        target_key = f"{source_key}.gz"
        
        try:
            # 1. 获取源S3对象的流式响应(不下载整个文件到本地)
            response = s3_client.get_object(Bucket=source_bucket, Key=source_key)
            source_stream = response['Body']
            
            # 2. 创建内存压缩流:将源流的数据实时压缩
            # 使用io.BytesIO作为缓冲,配合gzip.GzipFile实现流式压缩
            compressed_stream = io.BytesIO()
            with gzip.GzipFile(fileobj=compressed_stream, mode='wb', compresslevel=9) as gz:
                # 分块读取源流,避免一次性加载大文件到内存
                chunk_size = 1024 * 1024  # 1MB chunks,可根据内存调整
                while True:
                    chunk = source_stream.read(chunk_size)
                    if not chunk:
                        break
                    gz.write(chunk)
            
            # 重置压缩流的指针到开头,准备上传
            compressed_stream.seek(0)
            
            # 3. 流式上传压缩后的内容到目标桶
            s3_client.upload_fileobj(
                Fileobj=compressed_stream,
                Bucket=TARGET_BUCKET,
                Key=target_key,
                ExtraArgs={'ContentType': 'application/gzip'}
            )
            
            print(f"成功压缩并上传:{source_bucket}/{source_key} -> {TARGET_BUCKET}/{target_key}")
            
        except Exception as e:
            print(f"处理文件时出错:{str(e)}")
            raise e

关键配置说明

1. Lambda触发配置

  • 给你的Lambda函数添加S3触发器,选择源存储桶,触发事件类型为All object create events(或者更精确的Put事件)。
  • 注意:如果源桶和Lambda不在同一区域,需要在触发器配置中指定正确的区域。

2. 环境变量设置

在Lambda的配置页面,添加环境变量TARGET_S3_BUCKET,值为你的目标存储桶名称,这样不用硬编码在代码里,更灵活。

3. IAM权限配置

确保Lambda的执行角色拥有以下权限(可以通过IAM策略添加):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::你的源桶名称/*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::你的目标桶名称/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        }
    ]
}

4. Lambda性能调优

  • 内存设置:Lambda的内存越大,分配的CPU和网络带宽越高,处理大文件时建议设置为1024MB或更高,提升流式处理速度。
  • 超时时间:根据你处理的文件大小调整,比如处理1GB的文件,可能需要设置5-10分钟的超时(Lambda最大支持15分钟)。
  • 压缩级别:代码中compresslevel=9是最高压缩比,如果你更看重速度,可以改成compresslevel=1(最快压缩,压缩比稍低)。

测试验证

  1. 上传一个测试文件到源存储桶。
  2. 查看Lambda的CloudWatch日志,确认没有报错,且输出了成功的日志信息。
  3. 检查目标存储桶,确认生成了对应的.gz压缩文件,下载解压后验证内容和原文件一致。

内容的提问来源于stack exchange,提问作者Manoj Dhake

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 18:13:12