我正在考虑使用“锁定”S3 对象,以防止对给定 S3 对象同时进行相同的操作。但我对这个技术方案的有效性抱有很大的怀疑。
更准确地说,在对对象进行操作开始时,将创建一个与对象名称和正在执行的操作类型相对应的锁定文件。
示例:在 myObject 上的 myOperation 开始时,将查找 lck/myObject/myOperation 对象,如果不存在则创建该对象。
无论成功与否,这个“锁”对象都会在操作结束时被销毁。
我知道标准解决方案是使用数据库,但应用程序当前没有数据库。因此,如果我只能处理与 S3 的一致性,这就足够了。
我担心的是这个锁对象系统将在多线程/可能还有多节点架构中运行。现在,我了解到 Amazon S3 支持“写后读一致性”。
这是否意味着,如果我的应用程序 1(节点 1)/线程 2 通过 Java Amazon S3 API 在给定存储桶上放置锁定对象,则该锁定对象将立即对使用相同 API 的其他线程和其他应用程序可见?
最佳答案
如果您在 2023 年来到这里,仍然认为使用 S3 进行锁是一个好主意,那么由于强化的一致性模型,这可以以一种有保证的无竞争条件的方式实现,并且无需任何获取锁期间强制等待。
- 确定锁的基本名称(例如
some-dir/interesting-object.lock
) - Writer 创建空对象
some-dir/interesting-object.lock.<uuid>
在桶里。<uuid>
可以为每个锁生成一次,也可以为每个写入器生成一次(我们假设写入器不会同时写入),这并不重要。 - 列出前缀为
some-dir/interesting-object.lock.
的对象 - 检查具有“我们的”UUID 的文件是否是最旧的
ModifiedTime
。在极不可能的情况下,两个ModifiedTime
s 相等,根据 UUID 的字典顺序打破平局。 - 如果上述检查成功,则您已获得锁。您现在可以做这项工作了。否则,就会有人抢先一步。
- 删除锁定文件(注意:这意味着如果获取失败,您应该立即删除锁定文件)。
这是有效的,因为它保证一旦 put 成功,它将立即显示在列表调用中,并且每个工作人员在 put 后都会执行列表。如果另一个编写者甚至在我们晚一纳秒写入对象,他们仍然 100% 保证在他们的列表调用中看到我们的对象首先在那里。
为了允许删除陈旧/过期的锁(这些锁应该在步骤 4 的检查中排除,并删除文件),这需要对关键部分的持续时间设置一个上限,尽管可以任意设置通过创建具有不同 UUID 的新锁定文件来延长锁定时间(当您可以删除旧锁定文件时会受到一些限制,但我现在懒得考虑这一点)。另外,为了确定锁是否陈旧/过期,不要依赖本地计算机的时间,而是使用 ModifiedTime
新创建的锁对象作为校准时钟源。
我并不是说在 S3 中使用锁定文件是一个好主意,但这并没有改变它是可能的事实。
关于java - 伪 "lock"对象可以在 Amazon S3 API 中使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45222819/