2

我们刚刚将一个 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

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

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

大多数有问题的图像至少为 1000x1000 像素。

4

3 回答 3

2

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

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

于 2014-07-11T03:58:27.833 回答
2

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

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


通过 CloudFront 提供 S3 存储桶

第 0 步:如果您还没有这样做,请确保您的存储桶名称符合命名存储桶的“最佳实践”。他们不一定在所有他们应该做的地方都清楚地表明这一点,但是一个糟糕的存储桶名称可能会完全破坏它与其他 Amazon Web Services 的互操作性。最好的办法是将您的存储桶命名为全小写且不会太长(<= 60 个字符左右)的名称。

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

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

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

第 3 步:将您的应用程序配置为从 CloudFront 而不是 S3 提供服务。这是最简单的部分,因为URLhttps://bucketname.s3.amazonaws.com/path从 由于我将 Django 与 和 结合使用,因此最终只需在以下位置设置 Cloudfront 域即可https://somerandomstring.cloudfront.net/pathCNAMEmedia.yourdomain.tlddjango-storagess3-botosettings.py

AWS_S3_CUSTOM_DOMAIN = 'd2ynhpzeiwwiom.cloudfront.net'

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

于 2014-07-13T10:26:29.807 回答
1

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

原始答案: 为什么带有 S3Boto 后端的 django-storages 的 default_storate.exists() 会导致大型 S3 存储桶出现内存错误?

于 2017-08-03T07:32:09.537 回答