我正在 Amazon S3 上实现一个数据库,需要并发访问我的索引对象(作为 S3 对象实现),所以我正在寻找一种方法来实现对 S3 对象的乐观锁定。
我最初的想法是利用 S3 versioning 机制,并且仅当对象版本与我读取时的版本匹配时才更新索引对象(使用 PUT 操作)。但是,根据 S3 文档,似乎 S3 版本控制不支持此功能:PUT 不能以特定版本为条件,并且始终更新对象的最新版本。
我的问题是:
是否可以使用S3版本控制实现这种乐观锁定(似乎不是因为缺少以版本号为条件的PUT)?
如果 1 不可能,我可以使用我自己的版本控制(版本号保存为 S3 对象标签或其他对象元数据)来实现它——这可能还需要以元数据值为条件的对象放置/更新。
如果 1 和 2 都不可能,我是否必须引入外部机制(例如 Zookeeper 或其他分布式锁定)来实现对 S3 对象的并发访问?这样做的最佳做法是什么?我考虑过使用单独的锁对象(实现为 S3 对象)来指示索引是否被锁定,但这种方案有一定的缺点。
我意识到之前有人问过类似的问题,例如,(AWS S3 中是否有乐观锁定?)。然而,由于 S3 现在采用了新的强一致性模型(写入、覆盖、列表和删除),以前的答案似乎不再有效。
仅使用 AWS S3 无法实现此目标。
您可以实施以下解决方法来实现此目的:
您可以在 AWS DynamoDB 或 AWS SSM Parameter Store 中维护一个锁定变量(以节省资金),该变量可以在 PUT 操作期间设为 TRUE/FALSE。
您可以在 S3 存储桶上启用版本控制,并维护 AWS DynamoDB 或 AWS SSM Parameter Store 中所有读取操作要读取的版本(以节省资金),并在 PUT 操作成功后更新该版本。您还可以通过不在 S3 上启用版本控制并通过在密钥名称中附加版本号作为后缀来创建新对象来实现此目的。
下面的方法怎么样?
让需要锁的相关服务称为 S1。
S1 有一个 UUID 作为内存中的静态变量 -
S1-UUID
.
首先阅读JSON格式的文件
s3://bucket/locks/lock.json
:{UUID:'1-2-3-4' , createdTime:yyyy-mm-dd-hh-mm-ss-ms}
;
JSON 中的
UUID
是否与S1-UUID
匹配?是的?那么你已经有了锁。返回真。如果字符串不匹配...
创建的锁是否超过中止时间?是的?然后移动到
step 5
。不?然后回来说你没有锁。返回 false.
将
S1-UUID
和当前时间写入JSON并写入s3://bucket/lock/lock.json
等待
250ms
--250,因为我从未见过S3延迟超过125ms;所以要花双倍的时间来安全行事。再次阅读lock.json
。如果 UUID 匹配S1-UUID
,则从 JSON 中读取 UUID,然后您将获得锁。返回真。如果不返回 false.
对于 HTTP API 调用,我将
abort time
设为 2sec
(因为 HTTP SLA 对我们的 API 来说是 2 秒)。对于具有更高 SLA 的 Spark 作业,我们设置 2 小时——因为 Spark 作业需要 2 小时才能完成。
** 如果有人想投反对票,请给出理由 **