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

如何高效复制AWS S3中指定最后修改日期的海量对象?

优化AWS S3指定日期对象复制的方案

你的Bash脚本效率低下主要有两个核心问题:

  1. 未处理分页:aws s3api list-objects-v2默认最多返回1000个对象,百万级存储桶下会直接漏掉大量符合条件的对象;
  2. 单线程串行执行:循环中逐个调用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);
  }
})();

方案优势

  • 原生异步并发,资源利用率更高;
  • 内置分页处理逻辑,确保获取所有目标对象;
  • 可灵活添加错误重试、进度监控等扩展功能;
  • 适合超大规模对象集(百万级)的复制场景。

注意事项

  1. 并发数调整:AWS S3默认允许较高的请求并发,但如果触发限流(返回429错误),需降低CONCURRENCY或CONCURRENCY_LIMIT的值;
  2. 权限配置:确保执行脚本的IAM角色/用户拥有源桶的s3:GetObject和目标桶的s3:PutObject权限;
  3. 跨区域复制:若跨区域复制,目标桶需开启版本控制(可选),且注意数据传输费用;
  4. 错误处理:生产环境中建议添加重试逻辑,避免因网络波动导致部分对象复制失败。

内容的提问来源于stack exchange,提问作者Chatar Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 10:50:46