django-storages
在运行时,我遇到使用S3Boto后端的内存泄漏default_storage.exists()
我在这里关注文档: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()函数,这会导致缩略图生成速度极慢.
为避免这种情况,您可以preload_metadata=False
在创建Storage
或设置时简单地传递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
如下:
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请求,这可能不是什么大问题.