【问题标题】:Hosting files on S3 and utilizing mysql在 S3 上托管文件并使用 mysql
【发布时间】:2014-11-06 11:32:10
【问题描述】:

这个问题可能太笼统了,但是这里……

我想接受用户上传的图像并将它们托管在 S3 上。这方面的最佳做法是什么?我在想以下几点:

Mysql - 创建一个包含所有图像元数据的表:

  • 自动递增 ID
  • 上传者的用户 ID
  • 指向其在 S3 中的位置的 slug 或路径
  • 其他图像元数据? (大小、宽度、高度等)

S3 - 创建一个新的存储桶来保存图像

网站后端 - 处理上传的逻辑:

  1. 接受用户上传、验证文件等
  2. 可选择处理图像(调整大小、转换等)
  3. 使用新的随机 slug 上传到相应的 S3 存储桶
  4. 如果成功,在mysql表中添加一条新记录

--

这是将 S3 用作带有我的 Web 服务的云提供商的标准做法吗? 如何确保数据库和 S3 彼此保持更新?例如,如果手动从数据库中删除一条记录会怎样?我应该如何处理孤立的 S3 对象?或者另一方面,如果从 S3 中删除图像但在 mysql 表中没有相应记录怎么办? 是否由我自己编写一个脚本来验证两个系统之间的完整性?

【问题讨论】:

  • "例如,如果手动从数据库中删除一条记录会怎样?"不要那样做?
  • 显然我不会那样做,但是您不为您的架构实施安全措施吗?看起来很短视,不是吗?
  • 如果我偶尔会收到一个孤立的 S3 文件,这将花费我一分钱。花几个小时进行检查以节省一分钱对我来说并不划算。 S3 的文档表明他们每 1 万年丢失一个文件,所以我不太担心事情会消失。
  • 我更担心数据的完整性,而不是成本。我不知道,也许这只是一个不必要的“优化”。
  • 不管怎样,你好像做过类似的事情。你觉得这种架构好看吗?

标签: mysql database amazon-web-services amazon-s3


【解决方案1】:

查看 Get Bucket/List Objects 调用返回的信息。

http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGET.html

特别是 Size、LastModified 和 ETag。

上传时将它们保存在表格中。

列出对象返回有关存储桶中对象的此信息,对象按顺序列出,每个请求最多 1000 个对象,然后您可以从上次中断的地方继续进行下一个请求。

每 1000 个请求 0.005 美元,您只需 0.04 美元就可以在 8000 个请求中审计一个包含 800 万个对象(例如我拥有的对象)的存储桶。

ETag 尤其重要,因为在 PUT 请求时,它会自动设置为对象主体的十六进制 md5 哈希。 (在多部分上传时,它是每个部分的串联二进制 md5 的十六进制 md5,后跟部分数)。有了这些易于获取的信息和大小,您就可以协调并合理地确保存储桶中的对象正是您认为的那样。

然后编写一个获取对象列表的脚本,并定期与数据库进行比较。

想到的另一个重要的最佳实践是不要让分散的代码接触数据库和 S3。将涉及这两个方面的代码放在一起。


其他与一致性相关的想法... S3 中的x-amz-meta-* 用户定义的标头非常有用;您可以在上传时设置它们,或者稍后通过 API 使用修改后的元数据“将对象复制到自身上”来修改它们。您可以为每个对象存储大约 8K 元数据,例如将其与包含它的数据库行相关联的 id。 “获取存储桶/列表对象”调用无法获得此信息,您必须针对特定对象发送 http HEAD 请求才能获取元数据......但如果您希望您可以找出一个搁浅的桶对象来自,保存该信息会很好。 警告,任何有权下载该对象的人也会在响应标头中获得元数据的副本(很容易看到他们是否正在查看),因此您应该将唯一的内容存储在公共或广泛可用的对象上将是琐碎且不敏感的事情。 x-amz-meta-image-id: 1337 可能是安全的,如果知道图像 id 没有特别的后果。同样,如果是调整大小的图像,存储原始源图像的 MD5 或 SHA 有助于程序验证,是的,“这个图像”是“那个图像”的调整大小版本,即使有人得到了这个特定的元数据,这没有任何实际意义,因为我们拥有所有相关图像的权利。任何敏感或个人数据不应存储在公共内容中,但在非公共对象上,元数据与对象本身一样安全。

【讨论】:

  • 感谢您的洞察力。您是否将每个对象的 S3 路径存储在数据库中?还是存储完整的 URL 以防您想要处理多个云提供商(或从 S3 切换到另一个服务)?
  • 这取决于应用程序。大多数时候,我存储我认为完整的“规范”URL,包括开头的 https://bucketname.s3-cc-region-xx.amazonaws.com/,因为这是完全明确的(不是最节省空间的,但通常是一个合理的权衡)。我提到的大桶的情况,我只存储路径,因为这些东西实际上是冗余存储在两个区域的两个桶中以及我主数据中心的物理服务器上,并且每个路径都相同位置。
  • 哦...说到 S3+MySQL,我实际上写了一个 MySQL 存储函数,给定一个 URI/URL,它将使用 S3 的 V2 查询字符串身份验证算法为 S3 对象生成一个签名的下载链接...本质上是SELECT sign_download_url('...'),因此您实际上可以直接从MySQL、查询甚至嵌入视图中获得按需生成的签名下载链接。我非常方便地将预签名的下载链接集成到现有系统中,但我们也经常将其用于新开发。
  • 谢谢迈克尔,非常感谢您的彻底回答。今后,此信息将非常方便。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 2011-11-06
  • 2013-07-27
  • 1970-01-01
  • 2013-06-20
  • 2015-12-22
  • 1970-01-01
相关资源
最近更新 更多