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

大文件仓库上传AWS Glacier时的压缩同步优化方案咨询

完全可行!针对你这种数百万文件、本地存储空间吃紧的备份场景,我们可以通过分目录压缩→上传验证→归档确认→即时清理的流程来实现——既减少了S3 API调用次数(压缩成单个文件比传数百万小文件成本低得多),又能避免压缩包长期占用本地空间。下面是两种具体的实现方案,你可以根据自己的技术栈选择:

方案一:Shell 脚本(基于 AWS CLI + 原生工具)

如果你熟悉命令行,这个方案零额外依赖,直接用系统自带的tar、find加上AWS CLI就能搞定,上手快。

完整脚本逻辑

#!/bin/bash
set -euo pipefail

BACKUP_BUCKET="backup"
LOG_FILE="backup_sync.log"

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# 遍历当前目录下的一级子目录(可根据你的目录结构调整-depth参数)
find . -type d -depth 1 -print0 | while IFS= read -r -d '' dir; do
    dir_name=$(basename "$dir")
    tarball="${dir_name}.tar.gz"
    log "开始处理目录:$dir_name"

    # 1. 压缩目录(用xz替换gz可获得更高压缩率,速度稍慢)
    log "正在压缩目录:$dir_name → $tarball"
    if ! tar -czf "$tarball" -C "$(dirname "$dir")" "$dir_name"; then
        log "压缩失败:$dir_name"
        continue
    fi

    # 2. 上传压缩包到S3 DEEP_ARCHIVE
    log "正在上传压缩包:$tarball"
    if ! aws s3 cp "$tarball" "s3://${BACKUP_BUCKET}/${tarball}" --storage-class DEEP_ARCHIVE; then
        log "上传失败:$tarball"
        continue
    fi

    # 3. 等待归档完成(DEEP_ARCHIVE是异步归档,需确认状态)
    log "等待归档完成:$tarball"
    archive_status=""
    while true; do
        archive_status=$(aws s3api head-object --bucket "$BACKUP_BUCKET" --key "$tarball" --query 'ArchiveStatus' --output text 2>/dev/null)
        if [ "$archive_status" = "COMPLETED" ]; then
            log "归档完成:$tarball"
            break
        elif [ "$archive_status" = "FAILED" ]; then
            log "归档失败:$tarball"
            break
        else
            log "归档中,10分钟后重试..."
            sleep 600
        fi
    done

    # 4. 验证上传完整性(可选但强烈推荐)
    if [ "$archive_status" = "COMPLETED" ]; then
        log "验证上传完整性:$tarball"
        local_hash=$(sha256sum "$tarball" | awk '{print $1}')
        s3_hash=$(aws s3 cp "s3://${BACKUP_BUCKET}/${tarball}" - | sha256sum | awk '{print $1}')
        if [ "$local_hash" = "$s3_hash" ]; then
            log "验证通过,删除本地压缩包:$tarball"
            rm -f "$tarball"
        else
            log "验证失败,保留压缩包:$tarball"
        fi
    else
        log "归档未完成,保留压缩包:$tarball"
    fi
done

log "所有目录处理完毕"

使用说明

  1. 把脚本保存为s3_glacier_backup.sh,赋予执行权限:chmod +x s3_glacier_backup.sh
  2. 调整BACKUP_BUCKET为你的S3桶名,根据需要修改压缩格式(-czf是gzip,换成-cJf是xz)
  3. 运行脚本:./s3_glacier_backup.sh,所有操作会记录到backup_sync.log中

方案二:Python 脚本(更灵活,适合复杂场景)

如果你的目录结构复杂,或者需要并行处理、精细的错误重试,用Python结合boto3库会更灵活。

核心代码示例

import os
import tarfile
import boto3
import time
import hashlib
from datetime import datetime

def log(message):
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(f"[{timestamp}] {message}")

def compress_directory(dir_path):
    dir_name = os.path.basename(dir_path)
    tarball_name = f"{dir_name}.tar.gz"
    try:
        with tarfile.open(tarball_name, 'w:gz') as tar:
            tar.add(dir_path, arcname=dir_name)
        log(f"压缩完成:{tarball_name}")
        return tarball_name
    except Exception as e:
        log(f"压缩失败:{dir_name} - {str(e)}")
        return None

def upload_and_wait_archive(s3_client, bucket_name, tarball_path):
    tarball_name = os.path.basename(tarball_path)
    try:
        s3_client.upload_file(
            tarball_path,
            bucket_name,
            tarball_name,
            ExtraArgs={'StorageClass': 'DEEP_ARCHIVE'}
        )
        log(f"上传完成:{tarball_name}")

        # 等待归档完成
        while True:
            response = s3_client.head_object(Bucket=bucket_name, Key=tarball_name)
            archive_status = response.get('ArchiveStatus')
            if archive_status == 'COMPLETED':
                log(f"归档完成:{tarball_name}")
                return True
            elif archive_status == 'FAILED':
                log(f"归档失败:{tarball_name}")
                return False
            else:
                log(f"归档中,10分钟后重试...")
                time.sleep(600)
    except Exception as e:
        log(f"上传失败:{tarball_name} - {str(e)}")
        return False

def verify_upload(s3_client, bucket_name, tarball_path):
    tarball_name = os.path.basename(tarball_path)
    try:
        # 计算本地文件哈希
        with open(tarball_path, 'rb') as f:
            local_hash = hashlib.sha256(f.read()).hexdigest()
        
        # 计算S3文件哈希
        s3_object = s3_client.get_object(Bucket=bucket_name, Key=tarball_name)
        s3_hash = hashlib.sha256(s3_object['Body'].read()).hexdigest()
        
        if local_hash == s3_hash:
            log(f"验证通过:{tarball_name}")
            return True
        else:
            log(f"验证失败:{tarball_name}(本地哈希:{local_hash} | S3哈希:{s3_hash})")
            return False
    except Exception as e:
        log(f"验证出错:{tarball_name} - {str(e)}")
        return False

if __name__ == "__main__":
    BUCKET_NAME = "backup"
    s3 = boto3.client('s3')

    # 遍历当前目录下的子目录(跳过隐藏目录)
    for item in os.listdir('.'):
        item_path = os.path.join('.', item)
        if os.path.isdir(item_path) and not item.startswith('.'):
            log(f"开始处理目录:{item}")
            tarball = compress_directory(item_path)
            if not tarball:
                continue
            
            if upload_and_wait_archive(s3, BUCKET_NAME, tarball):
                if verify_upload(s3, BUCKET_NAME, tarball):
                    os.remove(tarball)
                    log(f"已删除本地压缩包:{tarball}")
                else:
                    log(f"验证失败,保留压缩包:{tarball}")
            else:
                log(f"归档未完成,保留压缩包:{tarball}")
    
    log("所有目录处理完成")

使用说明

  1. 安装依赖:pip install boto3
  2. 配置AWS凭证(可以用aws configure或者环境变量)
  3. 修改BUCKET_NAME为你的S3桶名,运行脚本即可

关键注意事项

  • 并行处理:如果服务器有足够的CPU和带宽,可以加入并行逻辑(比如shell用xargs -P,Python用concurrent.futures),但要注意不要同时处理过多目录导致磁盘IO或网络拥堵。
  • 错误重试:对于上传或归档失败的情况,建议添加重试逻辑(比如shell用until循环,Python用tenacity库),避免单次失败就中断流程。
  • 目录结构映射:如果需要在S3上保留原目录层级,上传时要把压缩包放到对应的路径下(比如s3://backup/path/to/dir.tar.gz),可以在脚本中动态生成S3键。
  • 磁盘空间监控:压缩前建议检查本地剩余磁盘空间,确保能放下当前目录的压缩包,避免中途磁盘满了导致失败。
  • 成本优化:DEEP_ARCHIVE的检索成本较高,一定要确保压缩包上传完整,避免后续需要重新上传或检索。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:21:21