簡體   English   中英

為什么帶有帶有S3Boto后端的django-storages的default_storate.exists()會導致帶有大型S3存儲桶的內存錯誤?

[英]Why does default_storate.exists() with django-storages with S3Boto backend cause a memory error with a large S3 bucket?

運行default_storage.exists()時,使用S3Boto后端遇到了django-storages storages內存泄漏的情況

我在這里關注文檔: http : //django-storages.readthedocs.org/en/latest/backends/amazon-S3.html

這是我的設置文件的相關部分:

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'

這是我要重復的問題:

./manage.py shell

from django.core.files.storage import default_storage

# Check default storage is right
default_storage.connection
>>> S3Connection:s3.amazonaws.com

# Check I can write to a file
file = default_storage.open('storage_test_2014', 'w')
file.write("does this work?")
file.close()
file2 = default_storage.open('storage_test_2014', 'r')
file2.read()
>>> 'does this work?'

# Run the exists command
default_storage.exists("asdfjkl") # This file doesn't exist - but the same thing happens no matter what I put here - even if I put 'storage_test_2014'

# Memory usage of the python process creeps up over the next 45 seconds, until it nears 100%
# iPython shell then crashes
>>> Killed

我想到的唯一潛在問題是我的S3存儲桶中有93,000個項目-我想知道.exists是否只是下載整個文件列表以進行檢查? 如果是這種情況,肯定有其他方法嗎? 不幸的是,在生成新縮略圖時,sorl-thumbnail使用此.exists()函數,這會導致縮略圖生成非常慢。

更新(2017年1月23日)

為避免這種情況,您可以在創建Storage時簡單地傳遞preload_metadata=False ,或在設置中設置AWS_PRELOAD_METADATA = False

感謝@ r3mot在評論中的建議。

原始答案

實際上,這是因為S3BotoStorage.exists調用了S3BotoStorage.entries ,如下所示:

    @property
    def entries(self):
        """
        Get the locally cached files for the bucket.
        """
        if self.preload_metadata and not self._entries:
            self._entries = dict((self._decode_name(entry.key), entry)
                                for entry in self.bucket.list(prefix=self.location))

解決這種情況的最佳方法是將S3BotoStorage子類S3BotoStorage如下:

from storages.backends.s3boto import S3BotoStorage, parse_ts_extended


class MyS3BotoStorage(S3BotoStorage):
    def exists(self, name):
        name = self._normalize_name(self._clean_name(name))
        k = self.bucket.new_key(self._encode_name(name))
        return k.exists()

    def size(self, name):
        name = self._normalize_name(self._clean_name(name))
        return self.bucket.get_key(self._encode_name(name)).size

    def modified_time(self, name):
        name = self._normalize_name(self._clean_name(name))
        k = self.bucket.get_key(self._encode_name(name))
        return parse_ts_extended(k.last_modified)

您只需要將此子類放入應用程序的一個模塊中,然后在設置模塊中通過點划線引用即可。 該子類的唯一缺點是,對3個覆蓋方法中的任何一個的每次調用都將導致Web請求,這可能沒什么大不了的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM