如何使用shell脚本检查Amazon S3文件(小.xml文件)是否被修改?我目前使用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中建立一个处理程序?)
4条答案
按热度按时间tp5buhyn1#
让我首先告诉您一些关于S3的事实。您可能知道这一点,但如果您不知道,您可能会看到您当前的代码可能有一些“意外”的行为。
S3和“最终一致性”
S3为被覆盖的对象提供“最终一致性”。在S3 FAQ中,您可以:
问:Amazon S3采用什么数据一致性模型?
所有区域中的Amazon S3存储桶为新对象的PUTS提供写后读一致性,并为覆盖PUTS和DELETES***提供 * 最终一致性。
覆盖的最终一致性意味着,无论何时更新对象(即,每当你的小XML文件被覆盖时),客户端检索文件可能会看到新版本,也可能会看到旧版本。持续多久?持续 * 未指定 * 的时间。它通常在远少于10秒的时间内实现一致性,但你必须假设它最终会,需要超过10秒钟才能达到一致性。更有趣的是(可悲的是?),即使 * 在 * 成功检索到新版本后,客户端可能以后仍然会收到旧版本。
有一件事你可以肯定:如果客户端 * 开始 * 下载文件某个版本,它将下载整个版本(换句话说,您不可能收到XML文件的前半部分作为旧版本,后半部分作为新版本)。
记住这一点,注意您的脚本可能无法在10秒的时间范围内识别更改:你可以多次请求,甚至在一次修改之后,直到你的脚本下载一个修改过的版本。2即使这样,在你检测到修改之后,下一个请求完全有可能下载 * 以前的 *(!3)版本,并触发你代码中的另一个“修改”,然后下一个请求将给予当前版本,并触发你代码中的另一个“修改”!
如果您对S3提供最终一致性这一事实没有意见,那么有一种方法可以改进您的系统。
创意一:S3事件通知+ SNS
你提到你考虑使用SNS。这绝对是一个有趣的方法:您可以启用S3事件通知,然后在文件更新时通过SNS获得通知。
您如何获得通知?您需要创建订阅,这里有几个选项。
创意1.1:S3事件通知+ SNS +“网络应用程序”
如果你有一个“网络应用程序”,即任何运行在一个公共可访问的HTTP端点,你可以创建一个HTTP订阅者,这样SNS就会调用你的服务器,并在它发生时发出通知。这在你的场景中可能是可能的,也可能不是理想的
想法2:S3事件通知+ SQS
您可以在SQS中创建一个消息队列,并让S3将通知直接发送到该队列。由于您可以将队列添加为SNS主题的订阅者,因此这也可以是 S3事件通知+ SNS + SQS(优点在于,万一你以后需要添加功能,你可以添加更多的队列并将它们订阅到相同的主题,因此获得通知的“多个副本”)。
要检索通知,您需要调用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编写代码(有些人设计了一些“黑客”来使用其他语言,包括Bash)。
这样做的好处是不再需要轮询,也不必维护web服务器(如“idea 1.1”中那样),只要有变化,代码就“简单地运行”。
请注意,无论您使用哪种方法,您仍然需要处理最终的一致性问题,换句话说,您知道 * PUT/POST已经发生 *,但是一旦代码发送了GET,您仍然可以收到旧版本......
想法4:改用DynamoDB
如果您有能力对系统进行更多的结构性更改,则可以考虑使用DynamoDB来完成此任务。
我建议这样做的原因是因为DynamoDB支持强一致性,即使是更新。注意,这不是默认的-默认情况下,DynamoDB在最终一致性模式下运行,但“检索”操作(例如GetItem)支持完全一致的读取。
此外,DynamoDB还具有我们称为“DynamoDB流”的功能,这是一种允许您获取对任何这些通知可以被轮询,或者它们甚至可以与Lambda函数一起使用,只要发生更改,Lambda函数就会自动调用!这一点,加上DynamoDB可以以很强的一致性使用,也许能帮你解决问题。
在DynamoDB中,保持记录较小通常是一个很好的实践。您在评论中提到您的XML文件大约为2kB -我认为这可以被认为“足够小”,因此它非常适合DynamoDB!(理由是:DynamoDB读取通常计算为4kB的倍数;因此要完全读取1个XML文件,只需读取1次;另外,根据您的操作方式,例如使用Query操作而不是GetItem操作,您可能能够从DynamoDB中读取2个XML文件,而只消耗1个读取操作)。
一些参考文献:
deyfvvtc2#
我可以通过使用S3 Versioning想到另一种方法;这将需要对您的代码进行最少量的更改。
版本控制是一种将对象的多个变体保存在同一存储桶中的方法。
这意味着每次上传新的
file.xml
时,S3都会创建一个新版本。在脚本中,获取包含**
VersionId
**字段的对象的HEAD,而不是获取对象并进行比较。将此版本与以前的版本进行匹配,以确定文件是否已更改。如果文件确实发生了更改,则获取新文件,同时获取该文件的新版本并将其保存在本地,以便下次可以使用此版本检查是否已上载更新的版本。
**注1:**您仍然会对S3进行大量调用,但不是每次都获取整个文件,而是只获取文件的元数据,这样速度更快,大小更小。
**注2:**然而,如果您的目标是减少调用次数,我能想到的最简单的解决方案是使用lambda。您可以在每次上传文件时触发lambda函数,然后调用服务的REST端点来通知您文件的更改。
kgqe7b3p3#
您可以使用--exact-timestamp,请参阅AWS讨论https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html
deikduxw4#
不使用版本控制,您可以简单地比较文件的E标签,它在文件头中可用,类似于文件的MD-5哈希(如果文件很小,即小于4 MB,有时甚至更大,则完全是MD-5哈希。否则,它是块的二进制哈希列表的MD-5哈希)。
话虽如此,我还是建议您再次查看您的应用程序,并询问是否有方法可以避免这条关键路径。