【问题标题】:Thread safe file rename in Amazon Web Services S3Amazon Web Services S3 中的线程安全文件重命名
【发布时间】:2016-06-25 14:47:27
【问题描述】:

我需要在 AWS S3 存储中移动重命名对象。

我找到的所有解决方案都需要先复制后删除。但是,这会导致两个文件都存在的时间很短,我认为这不是线程安全的。

有没有办法以线程安全的方式做到这一点?

代码在 Scala 中使用 Java AWS 开发工具包。

编辑: Rob,感谢您的回复,我相信我理解代码在做什么,但让我觉得我问错了问题。

让我根据我想要完成的任务来描述它,而不是特定的 AWS 功能。

我有一个 S3 目录,它定期从外部源接收文件。我有多个需要“处理”这些文件的进程,每个文件应该只处理一次。

过去,作为一种廉价的处理方式,我使用重命名来移动文件或将其标记为正在处理。如果重命名成功,则该进程知道它“拥有”该文件并将继续处理。如果因为源文件不存在而失败,那么它将尝试目录中的下一个文件。

我需要的是一种方法,最好是仅限 S3,它允许多个进程处理文件,同时确保每个文件只处理一次。

在您下面的解决方案中,由于 'find' 和 'delete' 是单独的方法,如果文件不存在,删除不会失败,我不确定我是否看到这两个进程不能简单(最坏的情况案例场景)都与另一个同步完成。

文件移动可能是错误的解决方案,而且我对 AWS 的缺乏经验使我无法找到完成此任务的更好方法。

【问题讨论】:

    标签: java scala amazon-web-services amazon-s3 rename


    【解决方案1】:

    过去,作为一种廉价的处理方式,我使用了重命名来 移动文件或将其标记为正在处理。如果重命名 成功了,那么进程就知道它“拥有”该文件并且会 继续处理。如果它失败是因为源文件没有 存在,那么它会尝试目录中的下一个文件。

    首先让我指出,这种使用原子重命名线程来获取独占访问权以处理文件的技术是可行的,但它确实存在使文件未处理的风险。想象一下如果线程(或整个服务器)在重命名后立即死亡会发生什么。如果没有可靠的方法来跟踪哪些文件尚未完成并重试它们,您的系统将不会很有弹性。

    正如您所注意到的,S3 没有原子重命名操作,因此您常用的技术无法按您的意愿工作。

    S3 有一个很好的“通知”功能,可以配置。在您的情况下,您可能希望在创建文件时收到通知。通知可以传送到 SNS、SQS 或 Lambda。您可能需要 SQS 或 Lambda。使用 SQS,消息被添加到队列中,您可以让线程抓取并处理文件。 SQS 模型保证“至少一次”传递,并将重试传递,直到消息被删除(或超出队列时间)。 redeliver-if-not-deleted 时间是可配置的。请注意,SQS 有可能多次传递相同的消息 - 它们在过度传递而不是不传递消息方面犯了错误。如果可以不频繁地对文件进行双重处理,那么这对您来说可能很好。我们广泛使用了 SQS 队列并且很高兴。

    我不熟悉 Lambda 消息处理的详细语义。

    我建议您谷歌“S3 事件通知”了解更多详情。

    原始问题的原始答案:

    我不确定问题是“线程安全”——也许更多的是“事务完整性”?

    在任何情况下,您都认为进行 S3“原子”重命名并不明显是正确的。我认为你必须“挑选你的毒药”——要么你必须处理这样一个事实:1)你同时拥有旧的和新的副本,或者 2)你有一段时间既没有旧的也没有旧的。新副本。

    在任何一种情况下,您需要处理的一个关键问题是坚持您正在进行重命名的事实(直到确认重命名完成)。如果您在某个数据库中有一行代表该文件,那么您可以将状态保留在那里。以下假设您不想使用 S3 以外的任何东西来保持状态。

    您将实际复制文件两次,使用临时文件夹作为中间副本。您可以让单独的线程执行每个步骤(查找要处理的文件),或者使用单个线程检查各种条件并执行其余步骤。换句话说,您需要查找部分完成的重命名(但该线程未能完成)并从中断处继续。

    对于本例,我们将从 A 重命名为 B,并使用一个名为 tmp 的临时文件夹。

    如果您更喜欢同时拥有两个副本:

    1. Copy A to tmp/A-B (the file name has before and after names in it).
    2. Finding tmp/A-B: copy it to B.
    3. Finding tmp/A-B, A and B: delete A.
    4. Finding tmp/A-B, A is missing and B exists: delete tmp/A-B.
    

    如果您更喜欢暂时没有副本:

    1. Copy A to tmp/A-B.
    2. Finding tmp/A-B and A: delete A.
    3. Finding tmp/A-B and A is missing and B is missing: copy tmp/A-B to B.
    4. Finding tmp/A-B and A is missing and B exists: delete tmp/A-B.
    

    【讨论】:

    • 谢谢,我可能问错了问题。请看我上面的编辑。
    • 再次感谢。我会调查事件。我们有一个监控工作目录中文件的进程,因此如果它们变得太旧(线程在没有完成或清理的情况下死亡),我们会收到该问题的通知。由于这应该很少见,因此手动将文件移回 in 目录对我们来说是一个不错的解决方案。
    【解决方案2】:

    不,S3 API 不支持该功能

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-05
      • 2015-02-07
      • 2012-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-29
      相关资源
      最近更新 更多