1

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

  1. 没有交易

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

  3. 由于数据存储在 2 个位置,因此备份变得复杂

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

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

问题:

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

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

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

4

1 回答 1

11

tl;dr:别再担心了,“过早的优化是万恶之源”

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

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

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

一般来说,复制很少用于静态内容。对于一个高流量的网站,你有一个用于静态内容的专用服务器——Django 让这很容易,这就是 MEDIA_URL 和 STATIC_URL 的用途。即使您从同一 Web 服务器提供的媒体开始,最好由单独的虚拟主机完成(例如,将应用程序放在http://www.example.com,将媒体放在http ://static.example.com,即使两者都来自同一台机器)。

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

如果您选择遵循“存储在文件系统上”的建议,那么在部署之前不要担心这一点,到时候部署专家会在您身边。

这种方法的关注点是性能。

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

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

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

1 - 对于我的目的,什么是好的缓存工具?

小故事:这是静态内容,在网络层做缓存(CDN、反向缓存代理等)。这是专业网络工程师的问题,而不是开发人员的问题。

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

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

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

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

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

[更新]

非常好的点。我知道复制很少用于静态内容。但这不是重点。其他人对文件使用复制的频率对不复制/备份数据库是错误的事实没有影响。其他人可能会因为某些数据是二进制的而丢失 ACID;我不是。就我而言,这些文件是“数据库的”,因为有些数据库列的值引用了这些文件。如果备份硬盘驱动器很少做,这是否意味着我不应该备份我的硬盘驱动器?不!

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

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

如果您选择将图像存储在数据库中,那一切都很好。有取舍,但请放心,作为开发人员,您不必担心它们,这是 DevOps 的“操作”部分的问题。

于 2013-11-05T05:28:28.843 回答