使用 concurrent.futures 上传 200 万个文件(每个大约 30 KB 从 EC2 到 S3),ThreadPool 需要很多时间

Upload 2 million files (each approx 30 KB from a EC2 to S3 ) using concurrent.futures , ThreadPool takes a lot of time

我们有一个要求,需要上传大约 200 万个文件(每个大约 30 KB,从 EC2 实例到 S3)。我们正在使用 python、boto3 和 concurrent.futures 模块来尝试实现这一目标。以下为伪代码

import concurrent.futures
from concurrent.futures import ThreadPoolExecutor

class UploadToS3:

    def upload(self, file_path):
        try:
            s3 = boto3.resource('s3')
            bucket = s3.Bucket('xxxxxxxxxx')
            destination_file_path =  'yyyyy'
            bucket.upload_file(file_path,destination_file_path)
            del s3
        except (Exception)  as e :
            print(e)

    def upload_files(self, file_paths):
        with concurrent.futures.ThreadPoolExecutor(max_workers=2000) as executor:  
            tracker_futures = []  
            for file_path in file_paths:
                tracker_futures.append(executor.submit(self.upload,file_path)) 
        for future in concurrent.futures.as_completed(tracker_futures):
                tracker_futures.remove(future)
                del future

然而我们发现我们每小时只能上传约 78000 个文件,增加线程数没有太大影响,我们相信这是因为 GIL,当我们尝试使用 ProcessPoolExecutor 时,我们 运行 问题,因为 boto3 对象不可拾取。关于如何克服这种情况的任何建议

根据我的一般经验,这听起来确实不错 - ~ 每秒 21 个文件。

可能 更好的是:

  • 将 200 万个文件压缩(或以其他方式混合在一起)到一个巨大的存档文件中。
  • 将该存档文件上传到与 S3 存储桶位于同一 AWS 数据中心的 EC2 实例。
  • 在 EC2 实例上解压文件。
  • 运行 EC2 实例上的 Python 脚本。

这将减少每次小型 S3 上传的往返网络时间,因为所有内容都将在 AWS 中。但是,您仍然可以 运行 限制并发上传的数量 and/or 每秒上传的数量。

一般来说 - 从 DOS 到 Windows 再到 Linux 再到 S3,等等 - 很多很多的小文件往往需要 很多至 process/upload/etc。比在更少、更大的文件中存储相同数量的数据。

虽然 S3 似乎比许多其他系统做得更好,但您可能还想考虑设置 S3 文件夹,以便 200 万个文件不在(相当于)一个目录。但是,根据文件的命名方案和文件的最终用途,这可能会也可能不会那么容易。