【问题标题】:How to get multiple objects from S3 using boto3 get_object (Python 2.7)如何使用 boto3 get_object (Python 2.7) 从 S3 获取多个对象
【发布时间】:2018-05-21 09:07:39
【问题描述】:

我在 S3 中保存了成千上万个对象。我的要求是我需要加载这些对象的一个​​子集(介于 5 到 ~3000 之间)并读取每个对象的二进制内容。通过阅读 boto3/AWS CLI 文档,看起来不可能在一个请求中获取多个对象,因此目前我已将其实现为一个循环,该循环构造每个对象的键,然后对对象的请求读取对象的主体:

for column_key in outstanding_column_keys:
  try:
     s3_object_key = "%s%s-%s" % (path_prefix, key, column_key)
     data_object = self.s3_client.get_object(Bucket=bucket_key, Key=s3_object_key)
     metadata_dict = data_object["Metadata"]
     metadata_dict["key"] = column_key
     metadata_dict["version"] = float(metadata_dict["version"])
     metadata_dict["data"] = data_object["Body"].read()
     records.append(Record(metadata_dict))
   except Exception as exc:
     logger.info(exc)
if len(records) < len(column_keys):
  raise Exception("Some objects are missing!")

我的问题是,当我尝试获取多个对象(例如 5 个对象)时,我返回了 3 个对象,并且在我检查是否所有对象都已加载时,其中一些对象尚未处理。我在自定义异常中处理它。我想出了一个解决方案,将上面的代码 sn-p 包装在一个 while 循环中,因为我知道我需要的未完成的键:

while (len(outstanding_column_keys) > 0) and (load_attempts < 10):
 for column_key in outstanding_column_keys:
  try:
     s3_object_key = "%s%s-%s" % (path_prefix, key, column_key)
     data_object = self.s3_client.get_object(Bucket=bucket_key, Key=s3_object_key)
     metadata_dict = data_object["Metadata"]
     metadata_dict["key"] = column_key
     metadata_dict["version"] = float(metadata_dict["version"])
     metadata_dict["data"] = data_object["Body"].read()
     records.append(Record(metadata_dict))
   except Exception as exc:
     logger.info(exc)
if len(records) < len(column_keys):
  raise Exception("Some objects are missing!")

但我怀疑 S3 实际上仍在处理未完成的响应,而 while 循环会不必要地对 S3 已经在返回过程中的对象发出额外的请求。

我进行了单独调查以验证 get_object 请求是同步的,并且看起来它们是:

import boto3
import time
import os

s3_client = boto3.client('s3', aws_access_key_id=os.environ["S3_AWS_ACCESS_KEY_ID"], aws_secret_access_key=os.environ["S3_AWS_SECRET_ACCESS_KEY"])

print "Saving 3000 objects to S3..."
start = time.time()
for x in xrange(3000):
  key = "greeting_{}".format(x)
  s3_client.put_object(Body="HelloWorld!", Bucket='bucket_name', Key=key)
end = time.time()
print "Done saving 3000 objects to S3 in %s" % (end - start)

print "Sleeping for 20 seconds before trying to load the saved objects..."
time.sleep(20)

print "Loading the saved objects..."
arr = []
start_load = time.time()
for x in xrange(3000):
  key = "greeting_{}".format(x)
   try:
     obj = s3_client.get_object(Bucket='bucket_name', Key=key)
     arr.append(obj)
   except Exception as exc:
     print exc
end_load= time.time()
print "Done loading the saved objects. Found %s objects. Time taken - %s" % (len(arr), end_load - start_load)

我的问题和需要确认的是:

  • get_object 请求是否确实是同步的?如果是,那么我希望当我第一次检查加载的对象时 代码 sn -p 然后所有这些都应该返回。
  • 如果get_object 请求是异步的,那么我如何处理响应以避免向 S3 发出额外请求 仍在返回过程中的对象?
  • 我对 S3 的任何假设的进一步澄清/反驳也将不胜感激。

谢谢!

【问题讨论】:

    标签: python-2.7 amazon-web-services amazon-s3 boto3


    【解决方案1】:

    与 Javascript 不同,Python 会同步处理请求,除非您执行某种多线程处理(您在上面的 sn-p 中没有这样做)。在您的 for 循环中,您向s3_client.get_object 发出请求,该调用将阻塞,直到数据返回。由于records 数组比它应该的要小,这一定意味着抛出了一些异常,它应该被捕获在 except 块中:

    except Exception as exc:
        logger.info(exc)
    

    如果没有打印任何内容,可能是因为日志记录被配置为忽略 INFO 级别的消息。如果您没有看到任何错误,您可以尝试使用logger.error 进行打印。

    【讨论】:

      猜你喜欢
      • 2017-07-13
      • 1970-01-01
      • 2021-05-22
      • 1970-01-01
      • 2017-11-19
      • 2017-05-08
      • 2016-07-12
      • 1970-01-01
      • 2021-11-12
      相关资源
      最近更新 更多