如何限制tar分卷大小并通过管道无额外磁盘占用上传至S3
大文件保留时间戳迁移S3的无本地磁盘分卷上传方案
问题背景
迁移大量文件到S3存储时,需要完整保留文件c-time、m-time、权限等元数据属性,无法使用aws s3 sync命令,最初采用直接管道打包上传的方案:
sudo tar -c --use-compress-program=pigz -f - <folder>/ | aws s3 cp - s3://<bucket>/<path-to-folder>/
处理80GB以上文件夹时触发报错:
upload failed: - to s3://<bucket>/<path-to-folder>/<filename>.tar.gz An error occurred (InvalidArgument) when calling the UploadPart operation: Part number must be an integer between 1 and 10000, inclusive
问题根源有两点:
- S3分片上传的分片总数上限为10000,单文件过大时默认分片大小会触发该限制
- 传统tar格式单文件大小上限为68GB,超出后会出现兼容性问题
原有本地方案的局限
最初查到的split分卷方案需要先生成本地分卷文件,再逐一上传,会占用大量本地磁盘空间:
生成分卷命令:
tar cvzf - data/ | split --bytes=100GB - sda1.backup.tar.gz.
本地合并解压命令:
cat sda1.backup.tar.gz.* | tar xzvf -
直接将split输出通过管道传给aws s3 cp的写法无法生效,因为split默认将分卷写入本地文件,不会将分卷内容输出到标准输出。
全管道无落盘实现方案
使用split自带的--filter参数即可实现全程管道传输,不需要占用额外本地磁盘空间。该参数支持指定一个shell命令,split每生成一个固定大小的分卷,就会将当前分卷的内容传入该命令的标准输入,同时内置变量$FILE对应当前分卷的完整文件名。
上传命令
sudo tar -c --use-compress-program=pigz -f - <目标文件夹>/ | split -a 2 --bytes=20GB --filter='aws s3 cp - s3://<bucket名称>/<存储路径>/$FILE' - prefix.tar.gz.
参数说明:
-a 2:设置分卷后缀长度为2位,默认生成aa、ab、ac...格式的字母后缀,最多支持676个分卷,按单卷20GB计算可支持最大13.5TB的压缩包;如果需要支持更大体积,可调整为-a 3(3位后缀)即可--bytes=20GB:设置单个分卷大小为20GB,该数值远低于tar单文件68GB的上限,同时总容量上限可达20GB*10000=200PB,完全不会触发S3分片上传的分片数限制- 末尾的
-指定split从标准输入读取tar压缩流,prefix.tar.gz.为分卷文件名前缀,最终S3中存储的文件名为prefix.tar.gz.aa、prefix.tar.gz.ab格式,和本地split生成的命名规则完全一致 - 如果需要使用数字格式后缀(00、01、02...),在split参数中增加
-d即可
恢复解压命令
迁移完成后需要恢复文件时,同样可以通过全管道方式直接从S3拉取分卷流合并解压,不需要下载到本地:
# 字母后缀分卷用这个命令 aws s3 ls s3://<bucket名称>/<存储路径>/prefix.tar.gz. | awk '{print $4}' | sort | xargs -I {} aws s3 cp s3://<bucket名称>/<存储路径>/{} - | cat | tar -x --use-compress-program=pigz -f - -C <解压目标路径>
注意事项
- 单分卷大小建议设置在10GB~50GB区间,避免S3中生成过多小文件,同时兼顾上传容错性
- 该方案全程无中间文件写入本地磁盘,内存占用仅为pigz压缩所需的缓存空间,大文件迁移时不会占满本地存储
- tar打包过程会完整保留所有文件元数据,包括c-time、m-time、权限、软链接等属性,和本地打包的效果完全一致
内容的提问来源于stack exchange,提问作者pkal
相关产品推荐
相关产品推荐

