如何保持数据库和对象存储一致以避免孤立对象?

问题描述 投票:0回答:1

我正在编写一个在线文本编辑器。我想允许用户将内联图像和视频添加到文档中。我正在努力以可靠的方式实现这一点。

当前基础设施:

  • 文档数据库(postgres)(文本、标题、作者、引用的媒体对象列表
    S3
  • 存储图像/视频/文件的对象存储(S3)

电流:

  1. 用户创建一个新文档
  2. 用户进行了更改,但未保存。这些更改存储在
    localStorage
    中,因此刷新时不会丢失。
  3. 用户附加图像
  4. 图像在上传到
    S3
    (或同等内容)时会显示加载指示器
  5. 用户保存文档,数据保存到数据库中。对象不会被保存,只保存
    S3
    它们的 URL。

问题

  • 如果用户在保存之前删除文档,或者保存失败
    S3
    中将会出现未被任何文档引用的孤立文件。
  • “删除文档”操作现在必须从 Postgres
    S3
    中删除某些内容。由于您无法跨两个完全不同的服务执行事务,因此可以想象这样一种情况:postgres 删除成功,但
    S3
    删除失败,从而创建更多孤立对象。

尝试解决方案

  • 我尝试将媒体存储在
    localStorage
    中,并在保存文档时将它们全部提交。这样可以解决问题,但是
    localStorage
    限制在5-10mb,太小了。
  • 一个 reaper 守护进程,它查询数据库中对
    S3
    的引用,并将其与存储在
    S3
    中的对象交叉引用以查找孤立对象,并自动删除这些对象。

收割者守护进程可以工作,但感觉就像是黑客攻击。我真的不想管理一个全新的服务只是为了存储一些文件。有一个更好的方法吗?行业标准是什么?

如果重要的话,我正在使用 React+Typescript,并且文本编辑器是基于 DraftJS 构建的。

postgresql amazon-s3 large-files consistency orphan
1个回答
0
投票

这是我遇到的同一问题的解决方案。

首先,一些一般规则:

  1. 数据库是事实的来源。如果对象存储与数据库不一致,则对象存储是错误的。
  2. 只要事实只被创建,从不被删除,分布式一致性就很容易。请参阅保持冷静论文。

数据库存储有关对象的以下信息:

  1. 唯一的ID。 (不是哈希:同一文件的两次上传必须获得两个不同的 ID。通过内容寻址来删除重复对象超出了范围。)
  2. 上传时间戳。这是在将对象上传到对象 ID 下的对象存储后设置的。
  3. 删除时间戳。这是在从对象存储中删除对象之前
  4. 设置的。
  5. 时间戳是可选的,但一旦设置就不可变。

只要有上传时间戳且没有删除时间戳,该对象就可以使用。

它有效地经历以下状态:

数据库:不存在。对象存储:不存在。
  1. DB:分配的ID。操作系统:不存在。
  2. DB:分配的ID。操作系统:存在。
  3. 数据库:已上传。操作系统:存在。
  4. 数据库:已删除。操作系统:存在。
  5. 数据库:已删除。操作系统:不存在。
  6. 数据库:不存在。操作系统:不存在。
  7. 应用程序在这里需要执行两个操作:创建对象和删除对象。两者都是幂等的。

创作:

分配 ID。
  1. 将对象上传到对象存储。
  2. 添加上传时间戳。
  3. 删除:

添加下载时间戳。
  1. 从对象存储中删除对象。
  2. 从数据库中删除该记录。
  3. 这里发生了两个破坏性更新:

该对象已从对象存储中删除。这是纯粹的清理,因为数据库已经考虑要删除的对象。
  1. 该记录已从数据库中删除。此时,系统不再是分布式的,因为对象存储不再了解该对象。
© www.soinside.com 2019 - 2024. All rights reserved.