
本文介绍一种基于流式解压(stream-unzip)与 http 分块拉取的内存友好方案,避免 lambda 内存溢出,适用于 gb 级 zip 文件的无临时存储、边解压边上传场景。
本文介绍一种基于流式解压(stream-unzip)与 http 分块拉取的内存友好方案,避免 lambda 内存溢出,适用于 gb 级 zip 文件的无临时存储、边解压边上传场景。
在 AWS Lambda 中直接解压大型 ZIP 文件(如数百 MB 至数 GB)时,传统 zipfile.ZipFile 会将整个 ZIP 流加载进内存并解析中央目录,极易触发 MemoryError 或 Lambda 内存限制(最高 10 GB,但成本陡增)。根本问题在于:ZIP 是随机访问结构,而标准库 zipfile 默认需预读全部字节以定位文件条目——这与 Lambda 的无状态、内存受限特性天然冲突。
推荐方案:流式解压 + 预签名 URL + 分块传输
核心思路是绕过 boto3.get_object() 全量下载,改用 httpx.stream() 通过预签名 URL 流式获取 ZIP 字节,并借助 stream-unzip 库逐文件解压——它不依赖中央目录,而是实时解析 ZIP 流中的本地文件头,真正实现“边读边解”,内存占用恒定(通常
✅ 正确实现步骤
-
生成预签名 URL(替代 s3_resource.Object().get())
Lambda 函数需具备 s3:GetObject 权限,且 ZIP 文件需为公开可读或通过预签名授权:presigned_url = s3_client.generate_presigned_url( 'get_object', Params={'Bucket': 'bucket1', 'Key': 'large-file.zip'}, ExpiresIn=3600 # 1小时有效期,需大于解压耗时 ) -
流式拉取 + 解压 + 上传
使用 stream-unzip 处理分块 ZIP 流,每个解压出的文件以 BytesIO 缓冲后直传 S3:import boto3 import httpx from stream_unzip import stream_unzip from io import BytesIO s3_client = boto3.client('s3') SOURCE_BUCKET = 'bucket1' TARGET_BUCKET = 'bucket2' def lambda_handler(event, context): # 从事件中获取 ZIP 文件名(推荐方式) zip_key = event.get('zip_key') or 'large-file.zip' # 生成预签名 URL presigned_url = s3_client.generate_presigned_url( 'get_object', Params={'Bucket': SOURCE_BUCKET, 'Key': zip_key}, ExpiresIn=3600 ) def zipped_chunks(): with httpx.stream('GET', presigned_url) as r: for chunk in r.iter_bytes(chunk_size=65536): # 64KB 分块 yield chunk try: for file_name, file_size, unzipped_chunks in stream_unzip(zipped_chunks()): # 清理路径:防止目录遍历(安全关键!) safe_name = file_name.decode('utf-8').strip('/') if '..' in safe_name or safe_name.startswith('/'): raise ValueError(f"Unsafe filename: {safe_name}") target_key = f'unzipped/{safe_name}' buffer = BytesIO() # 流式写入缓冲区 for chunk in unzipped_chunks: buffer.write(chunk) buffer.seek(0) # 直传至目标 Bucket s3_client.upload_fileobj( buffer, Bucket=TARGET_BUCKET, Key=target_key ) print(f"✅ Uploaded: {target_key} ({file_size} bytes)") buffer.close() except Exception as e: print(f"❌ Failed to process {zip_key}: {str(e)}") raise
⚠️ 关键注意事项
- Lambda 配置:设置内存 ≥ 512 MB(stream-unzip 自身开销小,但网络缓冲和 S3 上传需额外空间),超时时间建议 ≥ 15 分钟(大文件解压+上传耗时不可控)。
- 安全性:必须校验解压出的 file_name,禁止 ../ 路径遍历攻击;生产环境建议添加文件类型白名单(如仅允许 .txt, .csv)。
- 错误恢复:当前为全量重试模式;如需断点续传,需记录已处理文件名到 DynamoDB 或 S3 Tag。
- 替代方案权衡:若 ZIP 含加密文件或非标准格式(如 ZIP64 扩展),stream-unzip 可能不支持,此时需考虑 ECS Fargate 或 Step Functions + Batch 组合方案。
此方法将内存峰值控制在常量级,实测可稳定处理 5 GB ZIP(Lambda 1024 MB 内存),是 Serverless 场景下解压大 ZIP 的工业级实践。











