存储在数据库中的图像的缓存情况

时间:2013-10-23 23:39:06

标签: django caching blob

Django处理用户上传的建议是将它们存储在文件系统中,并将文件系统路径存储在数据库列中。这有效,但提出了一些我不想处理的问题:

  1. 无交易

  2. 没有简单的方法可以使文件系统和数据库保持同步

  3. 由于数据存储在2个地方

  4. ,因此会使备份变得复杂

    我的解决方案是将图像存储为文本列(https://djangosnippets.org/snippets/1669/)中的base64编码字符串。这需要更多空间,但使复制变得简单。

    这种方法的关注点是性能。不希望在每个图像请求中访问数据库。我需要某种服务器端缓存系统以及合理的缓存头。例如,如果有人请求“/media/documents/earth.jpg”,则应首先查询缓存,如果找不到该文件,则应该命中数据库。

    问题:

    1. 出于我的目的,什么是好的缓存工具?

    2. 鉴于这些要求是否要求每个图像请求都通过我的Django应用程序?或者是否有一个缓存工具,我可以用来防止这种情况。我有某些文件只能由某些人访问。对于这些我认为请求必须通过应用程序,因为没有其他方法来检查authorizaton。

    3. 如果此工具将文件缓存到文件系统,那么散列目录是否足以缓解一个目录中包含太多文件的问题?例如,elephant.gif的散列目录路径可能是/e/el/elephant.gif。

1 个答案:

答案 0 :(得分:12)

tl; dr:停止担忧和交付,"过早优化是所有邪恶的根源"

  

Django处理用户上传的建议是将它们存储在文件系统中,并将文件系统路径存储在数据库列中。

使用文件系统的建议是,您可以让Web服务器直接提供图像而不是应用程序提供的图像 - Web服务器非常非常擅长提供静态文件。

  

我的解决方案是将图像存储为文本列(https://djangosnippets.org/snippets/1669/)中的base64编码字符串。这需要更多空间,但使复制变得简单。

通常,复制很少用于静态内容。对于高流量网站,您有一个专用的静态内容服务器 - Django使这很容易,这就是MEDIA_URL和STATIC_URL的用途。即使您从同一个Web服务器提供的媒体开始,也可以通过单独的虚拟主机完成它(例如,将应用程序放在http://www.example.com,将媒体放在http://static.example.com即使从同一台机器上同时服务)。

Web服务器非常擅长提供静态内容,几乎不需要多个。在实践中,您很少会遇到专用服务器不再处理负载的程度,因为到那时您将使用CDN来削减带宽费用,而CDN将从服务器中消除大部分热量。

如果您选择关注文件系统上的"存储"建议,在部署之前不要担心这一点,当时间到来时,部署专家会在您身边。

  

这种方法的关注点是表现。

在数据库中存储静态内容为图像提供服务时所取得的性能:对于小文件来说,这几乎可以忽略不计 - 但是对于大文件,一个应用程序实例(或线程)将被卡住,直到下载完成。除非您的图片下载时间过长,否则不要担心。

  

不希望为每个图像请求访问数据库。

老实说,为什么呢?数据库旨在获取点击率。当您选择在数据库中存储图像时,性能掌握在DBA手中;作为开发人员,你应该停止思考它。何时(以及如果)您遇到与数据库问题相关的任何性能瓶颈,请咨询专业DBA,他将解决此问题。

  

1 - 为了我的目的,什么是好的缓存工具?

短篇小说:这是静态内容,在网络层执行缓存(CDN,反向缓存代理等)。对于专业网络工程师而言,这是一个问题,而不是开发人员。

Django有许多流行的缓存后端,恕我直言,它们对静态内容来说太过分了。

  

2 - 鉴于这些要求,每个图像请求都需要通过我的Django应用程序吗?或者是否有一个缓存工具,我可以用来防止这种情况。我有某些文件只能由某些人访问。对于这些,我假设请求必须通过应用程序,因为没有其他方法来检查authorizaton。

使用唯一且难以猜测的URL方案,例如,路径组件由文件内容的SHA2哈希加上一些秘密令牌组成。限制对您网站引用的请求的服务,以避免有人重新发布文件URL。如果合适,请使用过期标头。

  

3 - 如果此工具将文件缓存到文件系统,那么散列目录是否足以缓解一个目录中包含太多文件的问题?例如,elephant.gif的散列目录路径可以是/e/el/elephant.gif。

再次问问自己,你为什么担心。缓存层对开发人员应该是透明的。我不知道Django的任何流行的缓存解决方案都没有很好地涵盖这样的基本问题。

[更新]

  

很好的一点。我知道复制很少用于静态内容。但这不是重点。其他人使用复制文件的频率对于不复制/备份数据库的错误没有影响。其他人可能因为丢失ACID而被罚款,因为一些数据是二进制的;我不是。就我而言,这些文件是数据库的#34;"因为有数据库列,其值引用文件。如果备份硬盘很少做,这是否意味着我不应该备份我的硬盘? NO!

您的担忧是有效的,我只是想解释为什么Django开发人员对这种安排有偏见(静态内容的专用网络服务器),Django开始在新闻出版行业,这种方法运作良好,因为它的比例是一个受信任的成千上万读者的出版商。

重要的是要注意推荐的方法(恕我直言)不是违反ACID 。好吧,当记录改变或删除时,Django不会删除存储在文件系统中的旧图像 - 但是当你删除记录时,PostgreSQL不会立即从磁盘中删除元组,它们只是标记为稍后被清理。可惜Django没有内置的"真空"对于图像,但是编写一般的图像非常困难,所以我支持核心团队 - 数据安全是第一位的。以数据库迁移为例:他们花了很长时间才将数据库迁移合并到Django中,因为它也是一个难题。虽然编写通用解决方案很难,但编写特定的解决方案是微不足道的 - 对于某些项目,我有一个"垃圾收集器"我在低流量时间从crontab运行的进程,这个脚本只删除了数据库中没有被元数据引用的所有文件 - 这个脏的cron作业对我来说足够一致。

如果您选择在数据库中存储图像,那就很好了。有一些权衡,但请放心,你不必担心他们作为开发人员,这对于" ops" DevOps的一部分。