使用 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 万个文件不在(相当于)一个目录。但是,根据文件的命名方案和文件的最终用途,这可能会也可能不会那么容易。
我们有一个要求,需要上传大约 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 万个文件不在(相当于)一个目录。但是,根据文件的命名方案和文件的最终用途,这可能会也可能不会那么容易。