基于AWS CLI流式处理S3中1TB GZIP文件解压并重新上传的问题求助
先给你梳理下问题的核心,再提供几个实用的解决方案:
1. 先纠正你本地命令的错误
你本地执行的命令写法有误,正确的流式解压并上传到S3的命令应该是这样:
gzip -d < ./test.csv.gz | aws s3 cp - s3://test/test.csv
或者用gzip的-c参数(将解压内容输出到标准输出):
gzip -dc ./test.csv.gz | aws s3 cp - s3://test/test.csv
2. EC2进程被终止的核心原因:内存不足
你之前处理tar.gz顺利,本质是因为tar会逐个提取归档里的小文件(38GB×100个),每个小文件解压后立即上传,内存只需要处理单个小文件的数据,压力很小。但单个大型GZIP文件解压时,整个解压后的数据流会通过管道传输,如果EC2实例的内存不足以缓冲这些数据,系统的OOM Killer(内存不足杀手进程)就会直接终止你的进程。
针对这个问题的解决办法:
(1)调整AWS CLI的缓冲区大小
给aws s3 cp加上--buffer-size参数,限制单块数据的内存占用,比如设置为16MB:
aws s3 cp s3://test/test/csv.gz --buffer-size 16MB - | gzip -d | aws s3 cp --buffer-size 16MB - s3://test/test.csv
这个参数会让AWS CLI分块处理数据,避免一次性占用过多内存。
(2)用多线程解压工具pigz替换gzip
pigz是gzip的多线程版本,不仅解压速度更快,内存管理也更高效。先在EC2上安装pigz(比如yum install pigz或apt install pigz),然后执行命令:
aws s3 cp s3://test/test/csv.gz - | pigz -d | aws s3 cp - s3://test/test.csv
如果内存还是紧张,可以加上-p参数指定线程数,比如pigz -d -p 4限制为4线程。
(3)用磁盘中转代替纯流式处理
如果EC2内存实在不够,最稳妥的方式是先把GZ文件下载到磁盘(或者挂载的Amazon EFS),解压后再上传到S3,这样内存只需要处理当前解压的块,压力大幅降低:
# 假设已经挂载了EFS到/mnt/efs aws s3 cp s3://test/test/csv.gz /mnt/efs/test.csv.gz gzip -d /mnt/efs/test.csv.gz aws s3 cp /mnt/efs/test.csv s3://test/test.csv # 清理临时文件 rm /mnt/efs/test.csv
(4)升级EC2实例类型
如果经常处理这类超大文件,直接升级到内存更大的EC2实例(比如m5.2xlarge及以上),从根源上解决内存不足的问题。
3. 关于--expected-size参数的说明
你添加的--expected-size主要是让AWS CLI提前知道文件大小,优化进度条显示和预分配资源,它并不能解决内存不足的问题,所以即使设置了这个参数,进程还是会被OOM Killer终止。
内容的提问来源于stack exchange,提问作者user15793580

