检查S3文件是否已被修改

时间:2016-07-16 04:39:17

标签: bash shell amazon-s3

如何修改Amazon S3文件(小.xml文件),如何使用shell脚本检查。我目前正在使用curl每10秒检查一次,但它会发出许多GET请求。

curl "s3.aws.amazon.com/bucket/file.xml"
if cmp "file.xml" "current.xml"
then
     echo "no change"
else
     echo "file changed"
     cp "file.xml" "current.xml"
fi 
sleep(10s)

有没有更好的方法来检查每10秒减少GET请求的数量? (这是建立在rails应用程序之上,所以我可以在rails中构建一个处理程序?)

3 个答案:

答案 0 :(得分:4)

首先让我先告诉你一些关于S3的事实。你可能知道这一点,但是如果你不知道,你可能会发现你当前的代码可能有一些"意外的"行为。

S3和"最终一致性"

S3提供"最终的一致性"对于覆盖的对象。从S3 FAQ开始,您有:

  

问:Amazon S3采用什么数据一致性模型?

     

所有区域中的Amazon S3存储桶为新对象的PUTS提供了读写后一致性,并为覆盖PUTS和DELETES 提供了 最终一致性。

覆盖的最终一致性意味着,每当更新对象时(即,只要您的小XML文件被覆盖),检索文件的客户端可能会看到新版本,或者他们可能会看到旧版本。多长时间?对于未指定的时间量。它通常在不到10秒的时间内实现一致性,但您必须假设最终需要10秒以上才能实现一致性。更有趣的是(遗憾的是?),即使成功检索到新版本之后,客户仍可能会在以后收到旧版本。

您可以放心的一件事是:如果客户启动下载该文件的版本,它将下载整个版本(换句话说,那里没有机会例如,您将收到XML文件的前半部分作为旧版本,后半部分作为新版本。“

考虑到这一点,请注意您的脚本可能无法在10秒的时间范围内识别更改:即使在更改之后,您也可以发出多个请求,直到脚本下载更改的版本。即便如此,在您检测到更改后,(不幸的是)完全有可能下一个请求将下载之前的(!)版本,并触发另一个"更改"在你的代码中,然后下一个将给出当前版本,并触发另一个"更改"在你的代码中!

如果您对S3提供最终一致性的事实感到满意,那么可以采用一种方法来改进您的系统。

想法1:S3事件通知+ SNS

您提到过您考虑过使用SNS。这肯定是一个有趣的方法:您可以启用S3事件通知,然后在文件更新时通过SNS获得通知。

您如何收到通知?您需要创建订阅,这里有几个选项。

创意1.1:S3事件通知+ SNS + a"网络应用"

如果您有一个" Web应用程序",即在公共可访问的HTTP端点中运行的任何内容,您可以创建一个HTTP订阅者,因此SNS会在发生时通知您的服务器。在您的方案中,这可能是也可能是不可能的,也可能是不可取的

想法2:S3事件通知+ SQS

您可以在SQS中创建一个消息队列,并让S3将通知直接发送到队列。这也可以作为 S3事件通知+ SNS + SQS ,因为您可以将队列添加为SNS主题的订阅者(优点是,如果您以后需要添加功能,可以添加更多队列并将它们订阅到同一主题,从而获得#34;通知的多份副本。

要检索通知,您可以拨打SQS。您仍然需要轮询 - 即,有一个循环并在SQS上调用GET(其成本大致相同,或者可能比S3 GET更多,具体取决于区域)。稍有不同的是,您可以减少总请求的数量 - SQS支持长达20秒的长轮询请求:您在SQS上进行GET调用,如果没有消息,SQS保持最多20秒的请求,如果消息到达则立即返回,或者如果在20秒内没有可用消息则返回空响应。因此,您每20秒只发送1 GET,以获得比您目前更快的通知。您可以将所做的GET数量减半(每隔10到S3一次,每20秒到SQS一次)。

此外 - 您可以选择使用一个SQS队列来聚合所有XML文件或多个SQS队列的所有更改,每个XML文件一个。使用单个队列,您将极大地减少GET请求的总数。每个XML文件有一个队列,当你有可能"减半" GET请求的数量与您现在的数量相比。

创意3:S3事件通知+ AWS Lambda

您也可以使用Lambda函数。这可能需要对您的环境进行一些更改 - 您不会使用Shell脚本进行轮询,但可以将S3配置为为您调用Lambda函数作为对事件的响应,例如对XML文件的更新。你可以用Java,Javascript或Python编写你的代码(有些人设计了一些" hacks"也使用其他语言,包括Bash)。

这样做的好处在于,不再需要轮询,而且您不必维护Web服务器(如#14;想法1.1")。只要有变化,您的代码就会运行"

请注意,无论您使用哪种创意,仍然需要处理最终的一致性。换句话说,您知道 PUT / POST已经发生,但是一旦您的代码发送了GET,您仍然可以收到旧版本...

想法4:改为使用DynamoDB

如果您能够对系统进行更多结构性更改,则可以考虑使用DynamoDB执行此任务。

我之所以建议这是因为DynamoDB支持强一致性,即使是更新也是如此。请注意,它不是默认值 - 默认情况下,DynamoDB在最终一致性模式下运行,但是"检索"操作(例如,GetItem),支持完全一致的读取。

此外,DynamoDB具有我们所称的" DynamoDB Streams",这是一种机制,允许您获取对表中任何(或所有)项目所做的更改流。可以轮询这些通知,或者甚至可以将它们与Lambda函数结合使用,只要发生更改,就会自动调用它们!这一点,再加上DynamoDB可以使用强大的一致性,可能会帮助您解决问题。

在DynamoDB中,保持记录较小通常是一种很好的做法。您在评论中提到您的XML文件大约是2kB - 我说这可以被认为是#34;足够小"这样它非常适合DynamoDB! (推理:DynamoDB读取通常计算为4kB的倍数;因此要完全读取1个XML文件,您只需消耗1个读取;同样,取决于您的操作方式,例如使用Query操作一个GetItem操作,您可能能够从DynamoDB读取2个XML文件,只消耗1次读取操作。)

一些参考文献:

答案 1 :(得分:0)

我可以考虑使用S3 Versioning的另一种方式;这将需要对代码进行最少的更改。

  

版本控制是一种将对象的多个变体保留在同一存储桶中的方法。

这意味着每次上载新的file.xml时,S3都会创建一个新版本。

在脚本中,不要获取对象并进行比较,而要获取包含{strong> VersionId 字段的HEAD of the object。将此版本与以前的版本匹配,以查找文件是否已更改。

如果文件确实发生了更改,请获取新文件,并获取该文件的新版本并将其保存在本地,以便下次您可以使用此版本检查是否已上传了较新的版本。 / p>

注1:您仍将对S3进行大量调用,但不是每次都提取整个文件,而是仅提取文件中的元数据,该元数据的速度更快,更小。大小。

注释2:但是,如果您的目的是减少呼叫数量,那么我想到的最简单的解决方案是使用lambda。您可以在每次上传文件时触发lambda函数,然后调用服务的REST端点以通知您文件更改。

答案 2 :(得分:0)

您可以使用--exact-timestamps 查看AWS讨论 https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html