【问题标题】:default_storage.exists extremely slow and frequently times outdefault_storage.exists 非常慢并且经常超时
【发布时间】:2014-09-01 08:58:57
【问题描述】:

我们刚刚将一个 Django 项目迁移到 Heroku,并将我们所有的媒体和静态文件放在 Amazon S3 上(使用 django-storages 和 s3-boto)。

尽管我听说过 Amazon S3 速度非常快,并且在性能缓慢的情况下很少出现结果,但我们的图像加载速度已经减慢到绝对爬行并且经常超时。超时代码的一个例子是我们的一个模型上的这个属性,它试图选择一个合适的图像,最终回退到返回None

@property
def photo(self):
    """Transparently serve the best available image for templates"""
    if self.model_shot.storage.exists(self.model_shot.name):
        return self.model_shot
    elif self.image.storage.exists(self.image.name):
        return self.image
    else:
        return None

当我在一个导致问题的模型上进行测试时,我尝试了这个:

$ heroku run python manage.py shell
...
>>> design = Design.objects.get(pk=10210)
>>> design.photo

此命令导致 shell 在最终返回 ImageFieldFile 对象之前挂起几秒钟。对它的后续调用会立即返回,这让我相信结果被缓存了。

我的问题是,处理此问题的最佳方法是什么?我听说过很多关于在这种情况下使用 CloudFront 的信息,但这绝对不是因为高流量(我们的网站上应该基本上没有任何流量)。其他一些缓存框架?完全不同的东西?

大部分有问题的图片至少为 1000x1000 像素。

【问题讨论】:

    标签: python django amazon-s3 django-storage


    【解决方案1】:

    我在一个生产站点扩大规模时遇到了类似的问题。我建议使用存储后端,它可以维护自己的 S3 文件所有元信息的副本。最好的此类项目可能是MimicDB,尽管您也可以查看我对modified django-storages 所做的工作。这样一来,.exists().url 等元数据查询就会立即从本地缓存中得到答复。

    另外,请确保您通常只是获取 image 对象的 URL 或其他元数据,而不是使用任何会导致您的服务器不必要地获取实际图像数据的代码。设置此类事情时,我喜欢做的是修改 S3 包装器(例如 boto),以便它记录每个原始 S3 REST 请求,然后测试站点并确保仅查看站点上的网页不会导致来自 Web 服务器的任何 S3 请求。

    【讨论】:

    • 感谢您提出另一个我没有考虑过的想法。在昨天没有其他答案的情况下,我继续设置 CloudFront,我将完成这个 AM 的连接。如果这不起作用,下次会尝试。
    【解决方案2】:

    切换到 CloudFront 完全解决了这个问题,并且相对容易(没有代码更改,只是更多地使用 Amazon 控制台),所以我决定回答我自己的问题。

    tl;dr 不要直接从 S3 提供文件;设置 CloudFront。


    通过 CloudFront 提供 S3 存储桶

    第 0 步:如果您还没有这样做,请确保您的存储桶名称符合用于命名存储桶的 "best practices"。他们不一定在所有他们应该做的地方都清楚地表明这一点,但是一个糟糕的存储桶名称可能会完全破坏它与其他 Amazon Web 服务的互操作性。最好的办法是将存储桶命名为全小写且不会太长(

    第 1 步:为了让 CloudFront 提供存储桶中的文件,您需要将其设置为提供静态网站。您可以从存储桶的Permissions 选项卡在 Amazon AWS 控制台上执行此操作。亚马逊有几个地方有这方面的说明/文档; IMO 最清楚的是these重要提示:确保将默认根对象设置为 index.html - 该文件甚至不必存在,但该设置确实 em>。

    第 1.5 步 [可能是可选的]: 确保您的存储桶的权限正确无误。即使我从 S3 提供文件也没问题,但更改为 CloudFront 来提供它们会将所有内容都变成 403: Access Forbidden 错误。如果有疑问,并且您的文件不敏感,您可以在 AWS 控制台中右键单击存储桶的文件夹,然后单击 Make Public警告:这可能是一个非常耗时的过程,并且出于某些愚蠢的原因(即使是服务器端),您的浏览器会话必须保持打开。首先执行此操作,不要关闭您的会话。对于我们的存储桶,这大约需要 16 个小时。 :/

    第 2 步: 转到 AWS 控制台中的 Amazon CloudFront 部分,然后单击 Create Distribution 按钮。将其设为 Web 分发(默认)并使用您通过在上一步中为静态 Web 分发设置存储桶而生成的域作为源。同样,IMO,these 是 AWS 文档中最清晰、最直接的说明。您可以在此处保留几乎所有默认设置。创建完成后,只需等待它在控制台上列为“已部署”即可。

    第 3 步:将您的应用配置为从 CloudFront 而不是 S3 提供服务。这是最简单的部分,因为 URL 透明地从 https://bucketname.s3.amazonaws.com/path 移动到 https://somerandomstring.cloudfront.net/path(奖励:您可以将后者设置为 CNAME 记录以指向类似 media.yourdomain.tld 的内容;我们没有这样做我不会在这里讨论它)。由于我将 Django 与django-storagess3-boto 结合使用,因此这最终成为setting up that Cloudfront domain in settings.py 的简单问题:

    AWS_S3_CUSTOM_DOMAIN = 'd2ynhpzeiwwiom.cloudfront.net'
    

    就是这样!通过这些更改,我们所有的速度问题都消失了,我们的媒体丰富的页面(每页 6-20 MP 的图像)突然加载速度比以往任何时候都快!

    【讨论】:

      【解决方案3】:

      设置 AWS_PRELOAD_METADATA = False(默认值为 False),避免将存储桶中的所有文件元数据加载到内存中。这不仅会增加请求的等待时间,还会减少内存使用量。 在我的情况下,内存使用量从 ~1.5 GB 减少到 5-6MB,时间从 60 秒减少到 4-5 秒。

      原答案: Why does default_storate.exists() with django-storages with S3Boto backend cause a memory error with a large S3 bucket?

      【讨论】:

      • 这解决了我的问题,时间从 25 秒变为 0.2 秒。谢谢!
      猜你喜欢
      • 1970-01-01
      • 2012-05-25
      • 1970-01-01
      • 2012-02-25
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 2015-05-22
      相关资源
      最近更新 更多