如何高效复制AWS S3中指定最后修改日期的海量对象?
优化AWS S3指定日期对象复制的方案
你的Bash脚本效率低下主要有两个核心问题:
- 未处理分页:
aws s3api list-objects-v2默认最多返回1000个对象,百万级存储桶下会直接漏掉大量符合条件的对象; - 单线程串行执行:循环中逐个调用
copy-object,每个请求都是独立HTTP调用,完全无法利用S3的并发处理能力。
下面提供CLI和Node.js SDK两种优化方案,大幅提升复制效率。
一、CLI优化方案(并行化+分页处理)
通过分页获取所有目标对象,再用xargs实现批量并发复制:
#!/bin/bash SOURCE_BUCKET="b1" DESTINATION_BUCKET="b2" TARGET_DATE="2022-11-22" TEMP_FILE="/tmp/s3_objects_to_copy.txt" CONCURRENCY=100 # 并发数,可根据AWS配额调整(建议100-200) # 清空临时文件 > "$TEMP_FILE" # 分页遍历所有对象,筛选指定日期的Key next_token="" while true; do # 构造list-objects-v2命令参数 list_args=(--bucket "$SOURCE_BUCKET" --query 'Contents[?contains(LastModified, `'"$TARGET_DATE"'`)].Key' --output text) if [ -n "$next_token" ]; then list_args+=(--continuation-token "$next_token") fi # 获取当前页的对象Key response=$(aws s3api list-objects-v2 "${list_args[@]}") # 将结果追加到临时文件(过滤空行) echo "$response" | grep -v '^$' >> "$TEMP_FILE" # 检查是否还有下一页 is_truncated=$(aws s3api list-objects-v2 --bucket "$SOURCE_BUCKET" --query 'IsTruncated' --output text "${list_args[@]:2}") if [ "$is_truncated" = "false" ]; then break fi # 获取下一页的ContinuationToken next_token=$(aws s3api list-objects-v2 --bucket "$SOURCE_BUCKET" --query 'NextContinuationToken' --output text "${list_args[@]:2}") done # 并行执行复制操作 echo "Starting copy with $CONCURRENCY concurrent threads..." cat "$TEMP_FILE" | xargs -n 1 -P "$CONCURRENCY" bash -c ' file="$0" aws s3api copy-object \ --copy-source "'"$SOURCE_BUCKET"'/$file" \ --key "$file" \ --bucket "'"$DESTINATION_BUCKET"'" \ > /dev/null 2>&1 ' # 清理临时文件 rm "$TEMP_FILE" echo "Copy completed"
方案优势
- 自动处理分页,不会遗漏任何符合条件的对象;
- 用
xargs实现多线程并发复制,效率比原脚本提升数十倍; - 可通过
CONCURRENCY参数调整并发数,平衡速度与AWS请求限制。
二、Node.js SDK优化方案(异步并发)
Node.js的异步特性更适合处理大规模并发请求,配合AWS SDK v3可以高效完成复制任务:
首先安装依赖:
npm install @aws-sdk/client-s3 @aws-sdk/credential-provider-node
然后创建复制脚本:
const { S3Client, ListObjectsV2Command, CopyObjectCommand } = require("@aws-sdk/client-s3"); const { defaultProvider } = require("@aws-sdk/credential-provider-node"); // 配置参数 const CONFIG = { region: "us-east-1", // 替换为你的存储桶区域 credentials: defaultProvider(), }; const SOURCE_BUCKET = "b1"; const DESTINATION_BUCKET = "b2"; const TARGET_DATE = "2022-11-22"; const CONCURRENCY_LIMIT = 150; // 并发数,可根据需求调整 const s3Client = new S3Client(CONFIG); // 分页获取所有指定日期的对象Key async function fetchTargetKeys() { const keys = []; let nextToken; do { const listCommand = new ListObjectsV2Command({ Bucket: SOURCE_BUCKET, ContinuationToken: nextToken, }); const response = await s3Client.send(listCommand); if (!response.Contents) break; // 筛选LastModified为目标日期的对象 const filtered = response.Contents.filter(obj => obj.LastModified.toISOString().startsWith(TARGET_DATE) ).map(obj => obj.Key); keys.push(...filtered); nextToken = response.NextContinuationToken; } while (nextToken); return keys; } // 分批次并发复制对象 async function batchCopyObjects(keys) { // 按并发数拆分批次 for (let i = 0; i < keys.length; i += CONCURRENCY_LIMIT) { const batch = keys.slice(i, i + CONCURRENCY_LIMIT); console.log(`Processing batch ${Math.floor(i/CONCURRENCY_LIMIT)+1} (${batch.length} objects)`); // 并行执行当前批次的复制请求 await Promise.all(batch.map(key => { const copyCommand = new CopyObjectCommand({ Bucket: DESTINATION_BUCKET, Key: key, CopySource: `${SOURCE_BUCKET}/${key}`, }); return s3Client.send(copyCommand); })); } } // 主执行流程 (async () => { try { console.log("Fetching target objects..."); const targetKeys = await fetchTargetKeys(); console.log(`Found ${targetKeys.length} objects to copy`); if (targetKeys.length === 0) { console.log("No objects need to be copied"); return; } console.log("Starting copy process..."); await batchCopyObjects(targetKeys); console.log("All objects copied successfully"); } catch (err) { console.error("Copy failed:", err.message); process.exit(1); } })();
方案优势
- 原生异步并发,资源利用率更高;
- 内置分页处理逻辑,确保获取所有目标对象;
- 可灵活添加错误重试、进度监控等扩展功能;
- 适合超大规模对象集(百万级)的复制场景。
注意事项
- 并发数调整:AWS S3默认允许较高的请求并发,但如果触发限流(返回429错误),需降低
CONCURRENCY或CONCURRENCY_LIMIT的值; - 权限配置:确保执行脚本的IAM角色/用户拥有源桶的
s3:GetObject和目标桶的s3:PutObject权限; - 跨区域复制:若跨区域复制,目标桶需开启版本控制(可选),且注意数据传输费用;
- 错误处理:生产环境中建议添加重试逻辑,避免因网络波动导致部分对象复制失败。
内容的提问来源于stack exchange,提问作者Chatar Singh
相关产品推荐
相关产品推荐

